2170-Marked Ancestor

問題概要

頂点数が100000個以内の木が与えられる.
それに対し100000個以内の2種類の操作が与えられる
M:ある頂点をマークする,既にマークされている場合何もしない.
Q:ある頂点に対し祖先のうち最も近いマークがついた頂点の番号を求める.
Qの操作で求めた番号の総和を求めよ.

解法

前から考えるとUnion-Findの逆の分割の動作が必要になってしまい,解けないが,後ろから考えると単純にUnion-Findしていくだけで解ける.

実装(C++)

#include <algorithm>
#include <vector>
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
typedef long long int lli;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
int N,Q;
vector<int> children[100000];
int parent[100000];
char marked[100000],s[2];
int stack[100000],stc,a,b,init[100000];
char stack2[100000];
class UnionFind{
private:
	vector<int> par;vector<int> rank;
public:
	UnionFind(int n){
		par=vector<int>(n);rank=vector<int>(n,0);
		for(int i=0;i<n;i++){
			par[i]=i;
		}
	}
	int find(int x){
		if(par[x]==x)
			return x;
		else
			return par[x] = find(par[x]);
	}
	void unite(int x,int y){
		x=find(x);y=find(y);
		if(x==y)return;
		if(rank[x]<rank[y]){
			par[x]=y;
		} else{
			par[y]=x;
			if(rank[x]==rank[y]) rank[x]++;
		}
	}
	inline bool same(int x,int y){
		return find(x)==find(y);
	}
};
void bfs(int k,int value=0){
	queue<int> k_,value_;
	k_.push(k);value_.push(value);
	while(k_.empty()==false){
		value=value_.front();value_.pop();
		k=k_.front();k_.pop();

		if(marked[k]==true)value=k;
		init[k]=value;
		REP(i,children[k].size()){
			k_.push(children[k][i]);
			value_.push(value);
		}
	}
}
int main(){
	for(;;){
		scanf("%d%d",&N,&Q);stc=0;
		if(N==0)break;
		REP(i,N){
			children[i].clear();
			marked[i]=false;
		}
		REP(i,N-1){
			scanf("%d",&b);
			children[--b].push_back(i+1);
			parent[i+1]=b;
		}
		marked[0]=true;
		REP(i,Q){
			scanf("%s%d",s,&a);
			--a;
			if(s[0]=='M'&&marked[a])continue;
			if(s[0]=='M'){
				marked[a]=1;
			}
			stack2[stc]=s[0];
			stack[stc++]=a;
		}
		bfs(0,0);
		UnionFind uf(N);
		init[0]=0;
		REP(i,N){
			uf.unite(i,init[i]);
		}
		long long int ans=0;
		for(int i=--stc;i>=0;i--){
			if(stack2[i]=='Q'){
				ans+=init[uf.find(stack[i])]+1;
			}else{
				int v=init[uf.find(parent[stack[i]])];
				uf.unite(stack[i],parent[stack[i]]);
				init[uf.find(stack[i])]=v;
			}
		}
		cout<<ans<<endl;
	}
}