BJOI2014 大融合 并查集+线段树合并

大融合

Description

小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量。

这里写图片描述

例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因为有六条简单路径 2 -3- 8 , 2- 3 -8- 7 , 3- 8 , 3- 8 -7 , 4 -3- 8 , 4- 3 -8- 7 路过了边(3, 8 )。

现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。

Data Constraint

对于40%的数据, N ,Q 103
对于 100 %的数据, 1 N, Q 105

题解

首先先按照题目给出的所有边建出一棵树并求出 dfs 序。
对于询问操作,可以发现答案为儿子节点所在子树 Size *(父亲联通块大小-儿子节点所在子树 Size )。
不难发现某节点所在子树的所有节点 dfs 序是一段连续的区间,又因为某节点所在子树 Size 会因为修改操作的发生改变,因此我们可以采用线段树。
一开始对于每个点都种一颗线段树,修改操作其实就是将两棵线段树合并,同时维护每个点在所在联通块的祖先(即线段树的根),就能轻易地完成询问操作。
时间复杂度为 O (n log n <script type="math/tex" id="MathJax-Element-39">n</script>)。

Code(Pascal)

var
    dfx,dep,las:array[0..100100] of longint;
    xw:array[0..100000,1..3] of longint;
    n,q,i,j,k,l,o,p,a,b,w,tt,zz,d1,d2,qq:longint;
    root,fa,f:array[0..100100] of longint;
    tr:array[0..4800100,1..3] of longint;
    lb,be,la,ne:array[0..200100] of longint;  ch:char;
function max(a,b:longint):longint;
    begin
        if a>b then exit(a) else exit(b);
    end;
function gf(o:longint):longint;
    begin
        if f[o]=o then exit(o);
        f[o]:=gf(f[o]); exit(f[o]);
    end;
procedure dg(o,u:longint);
    var
        i:longint;
    begin
        inc(qq); dfx[o]:=qq; dep[o]:=u; las[o]:=qq; i:=be[o];
        while i<>0 do
        begin
            if fa[o]<>lb[i] then
            begin
                fa[lb[i]]:=o; dg(lb[i],u+1);
                las[o]:=max(las[o],las[lb[i]]);
            end;
            i:=ne[i];
        end;
    end;
procedure fk(p,l,r,mb:longint);
    var mid:longint;
    begin
        tr[p,3]:=1;
        if l=r then exit;
        inc(o); mid:=(l+r) div 2;
        if mb<=mid then
        begin tr[p,1]:=o; fk(o,l,mid,mb) end
        else begin tr[p,2]:=o; fk(o,mid+1,r,mb); end;
    end;
function ques(o,l,r,ll,rr:longint):longint;
    var ls,rs,mid:longint;
    begin
        if o=0 then exit(0);
        if (l=ll) and (r=rr) then exit(tr[o,3]);
        mid:=(l+r) div 2; ls:=tr[o,1]; rs:=tr[o,2];
        if rr<=mid then ques:=ques(ls,l,mid,ll,rr)
        else if ll>mid then ques:=ques(rs,mid+1,r,ll,rr)
        else ques:=ques(ls,l,mid,ll,mid)+ques(rs,mid+1,r,mid+1,rr);
    end;
function hb(x,y:longint):longint;
    begin
        if x=0 then exit(y);
        if y=0 then exit(x);
        tr[x,3]:=tr[x,3]+tr[y,3];
        tr[x][1]:=hb(tr[x][1],tr[y][1]);
        tr[x][2]:=hb(tr[x][2],tr[y][2]);
        exit(x);
    end;
begin
    readln(n,q);
    for i:=1 to q do
    begin
        read(ch); readln(a,b);
        if ch='A' then
        begin
            inc(o); ne[la[a]]:=o; la[a]:=o;
            lb[o]:=b; if be[a]=0 then be[a]:=o;
            inc(o); ne[la[b]]:=o; la[b]:=o;
            lb[o]:=a; if be[b]=0 then be[b]:=o;  xw[i,3]:=2;
        end else xw[i,3]:=1; xw[i,1]:=a; xw[i,2]:=b;
    end;   o:=0;
    for i:=1 to n do
    if fa[i]=0 then
    begin
        fa[i]:=-1; dg(i,1);
    end;
    for i:=1 to n do
    begin
        f[i]:=i; inc(o); root[i]:=o;
        fk(root[i],1,n,dfx[i]);
    end;
    for i:=1 to q do
    if xw[i,3]=1 then
    begin
        a:=xw[i,1]; b:=xw[i,2];
        if dep[a]>dep[b] then
        begin tt:=a; a:=b; b:=tt; end;
        zz:=gf(a); d1:=ques(root[zz],1,n,dfx[zz],las[zz]);
        d2:=ques(root[zz],1,n,dfx[b],las[b]);
        writeln(d2*(d1-d2));
    end
    else
    begin
        a:=xw[i,1]; b:=xw[i,2];
        if dep[a]>dep[b] then
        begin tt:=a; a:=b; b:=tt; end;
        zz:=gf(a); f[gf(b)]:=zz;
        root[zz]:=hb(root[zz],root[b]);
    end;
end.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值