JZOJ 4604 树【NOIP2016模拟7.11】

题目描述

这里写图片描述

输入格式

这里写图片描述

输出格式

这里写图片描述

样例输入

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.
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值