[BZOJ3091] 城市旅行

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=3091

题目大意

添边+删边+路径整体加+查询路径期望

题解

http://blog.csdn.net/popoqqq/article/details/40823659
ORZ PO姐

const
    maxn=50050;
var
    son:array[0..maxn,1..2]of longint;
    fa,rev:array[0..maxn]of longint;
    ans,sum,lsum,rsum,val,add,size:array[0..maxn]of int64;
    i,j,k:longint;
    n,m,a,b,c:longint;
    d:int64;
procedure swap(var a,b:longint);
var c:longint;
begin c:=a; a:=b; b:=c; end;

function gcd(a,b:int64):int64;
begin
    if b=0
    then gcd:=a
    else gcd:=gcd(b,a mod b);
end;

procedure addd(a:longint; b:int64);
begin
    sum[a]:=sum[a]+b*size[a];
    lsum[a]:=lsum[a]+b*(((1+size[a])*size[a])div 2);
    rsum[a]:=rsum[a]+b*(((1+size[a])*size[a])div 2);    
    ans[a]:=ans[a]+b*((size[a]*(size[a]+1)*(size[a]+2))div 6);
    val[a]:=val[a]+b;
    add[a]:=add[a]+b;
end;

procedure update(a:longint);
var ls,rs:longint;
begin
    if a=0 then exit; ls:=son[a,1]; rs:=son[a,2];
    ans[a]:=ans[ls]+ans[rs]+(size[rs]+1)*lsum[ls]+(size[ls]+1)*rsum[rs]+(size[ls]+1)*(size[rs]+1)*val[a];
    lsum[a]:=lsum[ls]+(sum[rs]+val[a])*(size[ls]+1)+lsum[rs];
    rsum[a]:=rsum[rs]+(sum[ls]+val[a])*(size[rs]+1)+rsum[ls];
    sum[a]:=sum[ls]+sum[rs]+val[a];
    size[a]:=size[ls]+size[rs]+1;
end;

procedure reserve(a:longint);
var b:int64;
begin
    swap(son[a,1],son[a,2]);
    b:=lsum[a]; lsum[a]:=rsum[a]; rsum[a]:=b;
    rev[a]:=rev[a] xor 1;
end;

procedure pushdown(a:longint);
begin
    if a=0 then exit;
    if rev[a]=1
    then
        begin
            if son[a,1]<>0 then reserve(son[a,1]);
            if son[a,2]<>0 then reserve(son[a,2]);          
            rev[a]:=0;
        end;
        if add[a]<>0
    then
        begin
            if son[a,1]<>0 then addd(son[a,1],add[a]);
            if son[a,2]<>0 then addd(son[a,2],add[a]);
            add[a]:=0;
        end;
end;

procedure rotate(a,kind:longint);
var b,c,unkind:longint;
begin
    b:=fa[a]; c:=fa[b]; unkind:=kind xor 3;
    if son[c,1]=b then son[c,1]:=a else
    if son[c,2]=b then son[c,2]:=a;
    fa[a]:=c; fa[b]:=a;
    fa[son[a,unkind]]:=b; son[b,kind]:=son[a,unkind]; son[a,unkind]:=b;
    update(b); update(a);
end;

function isroot(a:longint):longint;
begin if (son[fa[a],1]<>a)and(son[fa[a],2]<>a) then exit(1) else exit(0); end;

procedure splay(a:longint);
var b,kind,unkind:longint;
begin
    pushdown(a);
    while isroot(a)=0 do
        begin
            b:=fa[a]; pushdown(fa[b]); pushdown(b); pushdown(a);
            if son[b,1]=a then kind:=1 else kind:=2; unkind:=kind xor 3;
            if isroot(b)=1 then rotate(a,kind)
            else
                if son[fa[b],kind]=b
                then begin rotate(b,kind); rotate(a,kind); end
                else begin rotate(a,kind); rotate(a,unkind); end;
        end;
end;

procedure access(a:longint);
var b:longint;
begin
    splay(a); son[a,2]:=0; update(a);
    while fa[a]<>0 do
        begin
            b:=fa[a];
            splay(b);
            son[b,2]:=a;
            update(b);
            splay(a);
        end;
end;

procedure makeroot(a:longint);
begin
    access(a);
    reserve(a);
end;

function getroot(a:longint):longint;
begin
    access(a);
    while son[a,1]<>0 do
        a:=son[a,1];
    exit(a);
end;

procedure cut(a,b:longint);
begin
    makeroot(a);
    access(b);
    son[b,1]:=0; fa[a]:=0;
    update(b);
end;

procedure link(a,b:longint);
begin
    makeroot(a);
    fa[a]:=b;
end;

procedure work1(a,b:longint);
begin
    makeroot(a); access(b);
    if (son[b,1]=a)and(son[a,2]=0) then cut(a,b);
end;

procedure work2(a,b:longint);
begin
    if getroot(a)=getroot(b) then exit;
    link(a,b);
end;

procedure work3(a,b:longint; c:int64);
begin
    if getroot(a)<>getroot(b) then exit;
    makeroot(a); access(b); 
    pushdown(b);
    addd(b,c);
end;

procedure work4(a,b:longint);
var tt,c,d:int64;
begin
    if getroot(a)<>getroot(b) then begin writeln(-1); exit; end;
    makeroot(a); access(b); pushdown(b);
    c:=ans[b]; d:=((size[b]+1)*size[b])div 2; 
    tt:=gcd(c,d);
    c:=c div tt; d:=d div tt;
    writeln(c,'/',d);
end;

begin
    readln(n,m);
    for i:=1 to n do
        begin
            read(a);
            ans[i]:=a; sum[i]:=a; lsum[i]:=a; rsum[i]:=a; val[i]:=a; add[i]:=0; fa[i]:=0; rev[i]:=0; son[i,1]:=0; son[i,2]:=0; size[i]:=1;
        end;
     for i:=1 to n-1 do
        begin
            readln(a,b);
            link(a,b);
        end;
     for i:=1 to m do
        begin
            read(a);
            case a of
            1:begin readln(b,c); work1(b,c); end;
            2:begin readln(b,c); work2(b,c); end;
            3:begin readln(b,c,d); work3(b,c,d); end;
            4:begin readln(b,c); work4(b,c); end;
            end;
        end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值