树
题目描述
输入格式
输出格式
样例输入
5 5
1 2
1 3
2 4
2 5
Q 2
C 2
Q 2
Q 5
Q 3
样例输出
1
2
2
1
数据范围
题解
解法一:树链剖分,暴力维护即可,表示我不会,比赛时我打了解法二(出题人提供的正解)。
解法二:离线处理,并查集。
倒着过来做,先将所有需要标记的点全部标记,然后遍历一次,求出每个点最近的那个打了标记的祖先,并向其连一条边,连接到其集合内。
当一个点的标记消失时,将此点向它的父亲连一条边,表示加入他父亲的集合。
每次查询时,查找自己那个集合内的祖先,此祖先就是最近的那个打了标记的祖先,也就是答案。(此算法的正确性就不证明了,证明很简单,很显然,请读者自行思考)
Code(Pascal)
var
ch,cc:char;
n,m,q,i,j,k,l,o,p,oo:longint;
cz:array[0..101000,1..2] of longint;
bb,da,fa,ans,en:array[0..101000] of longint;
bj:array[0..201000,1..2] of longint;
procedure cqyadd(x,y:longint);
begin
inc(en[x]);
inc(en[y]);
inc(oo);
bj[oo,1]:=x;
bj[oo,2]:=y;
inc(oo);
bj[oo,1]:=y;
bj[oo,2]:=x;
end;
procedure bh;
var
i:longint;
begin
bb[1]:=1;
fa[1]:=1;
da[1]:=1;
randomize;
for i:=1 to n do
en[i]:=en[i-1]+en[i];
for i:=1 to m div 2 do
begin
k:=random(m div 2)+m div 2;
bj[0]:=bj[i];
bj[i]:=bj[k];
bj[k]:=bj[0];
end;
end;
procedure qsort(l,r:longint);
var
i,j,m:longint;
begin
i:=l;
j:=r;
m:=bj[(l+r) div 2,1];
repeat
while bj[i,1]<m do inc(i);
while bj[j,1]>m do dec(j);
if i<=j then
begin
bj[0]:=bj[i];
bj[i]:=bj[j];
bj[j]:=bj[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
procedure dg(o:longint);
var
i:longint;
begin
for i:=en[o-1]+1 to en[o] do
if da[bj[i,2]]=0 then
begin
da[bj[i,2]]:=o;
if fa[bj[i,2]]=0 then fa[bj[i,2]]:=fa[o];
dg(bj[i,2]);
end;
end;
function lookfor(o:longint):longint;
begin
if fa[o]=o then exit(o);
fa[o]:=lookfor(fa[o]);
exit(fa[o]);
end;
begin
readln(n,q);
for i:=1 to n-1 do
begin
readln(o,p);
cqyadd(o,p);
end;
m:=2*n-2;
bh;
qsort(1,m);
for i:=1 to q do
begin
read(ch);
read(cc);
readln(cz[i,2]);
if ch='C' then
begin
cz[i,1]:=1;
inc(bb[cz[i,2]]);
fa[cz[i,2]]:=cz[i,2];
end
else cz[i,1]:=2;
end;
dg(1);
for i:=q downto 1 do
begin
if cz[i,1]=2 then ans[i]:=lookfor(cz[i,2])
else
begin
dec(bb[cz[i,2]]);
if bb[cz[i,2]]=0 then
fa[cz[i,2]]:=fa[da[cz[i,2]]];
end;
end;
for i:=1 to q do
if cz[i,1]=2 then writeln(ans[i]);
end.