【NOIP2016提高A组集训第5场11.2】行走

这里写图片描述
Input

第一行两个整数n和q表示点个数和询问与操作个数
接下来n-1行每行三个整数u,v,c表示u与v之间有一条边权为c的边
接下来q行每行第一个数type
如果type=1那么接下来三个数x,y,v表示一组询问
如果type=2那么接下来两个数p,c表示一组操作

Output

对于每组询问输出一个数表示最后的答案

Sample Input

样例输入1
6 6
1 2 1
1 3 7
1 4 4
2 5 5
2 6 2
1 4 6 17
2 3 2
1 4 6 17
1 5 5 20
2 4 1
1 5 1 3
样例输入2
5 4
1 2 7
1 3 3
3 4 2
3 5 5
1 4 2 100
1 5 4 1
2 2 2
1 1 3 4

Sample Output

样例输出1
2
4
20
3
样例输出2
2
0
2

Data Constraint

对于70%的数据保证 n <= 1000
对于100%的数据保证 n,q <= 105 ,c_i,v_i <= 1018
保证每次修改后的边权小于等于原来的边权且不会小于1

题解

首先我们发现如果答案不为1那么路径上最多只有60个值不为1的边(否则最后的答案小于等于1)。那么我们可以对权值等于1的边并查集,然后对于每一对询问做一次lca,然后往上跑就可以了

贴代码

var
    fa,deep:array[0..100005]of longint;
    a,f,p:array[0..200005,1..3]of int64;
    b:array[0..100005,1..2]of longint;
    bz:array[0..100005]of boolean;
    ff:array[0..100005,0..18]of longint;
    cc:array[0..20]of longint;
    i,j,k,l,n,q,x,y,t1,t2,x1,y1:longint;
    z:int64;
procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2,1];
    repeat
        while a[i,1]<mid do inc(i);
        while a[j,1]>mid do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then qsort(i,r);
    if l<j then qsort(l,j);
end;
procedure star;
begin
    b[a[1,1],1]:=1;
    for i:=2 to 2*n-2 do
    if a[i,1]<>a[i-1,1] then
    begin
        b[a[i-1,1],2]:=i-1;
        b[a[i,1],1]:=i;
    end;
    b[a[2*n-2,1],2]:=2*n-2;
end;
procedure make_f(x:longint);
var
    i:longint;
begin
    bz[x]:=true;
    for i:=b[x,1] to b[x,2] do
    if (i<>0) and (bz[a[i,2]]=false) then
    begin
        f[a[i,2],1]:=x;
        f[a[i,2],2]:=a[i,3];
        deep[a[i,2]]:=deep[x]+1;
        make_f(a[i,2]);
    end;
end;
function getfather(x:longint):longint;
begin
    if fa[x]=x then exit(x)
    else fa[x]:=getfather(fa[x]);
    exit(fa[x]);
end;
procedure make_ff;
var
    i,j:longint;
begin
    for j:=1 to 17 do
        for i:=2 to n do ff[i,j]:=ff[ff[i,j-1],j-1];
end;
begin
    assign(input,'walk.in'); reset(input);
    assign(output,'walk.out'); rewrite(output);
    readln(n,q);
    for i:=1 to n-1 do
    begin
        readln(a[i,1],a[i,2],a[i,3]);
        a[i+n-1,1]:=a[i,2];
        a[i+n-1,2]:=a[i,1];
        a[i+n-1,3]:=a[i,3];
    end;
    p:=a;
    qsort(1,2*n-2);
    star;
    deep[1]:=1;
    make_f(1);
    for i:=1 to n do fa[i]:=i;
    for i:=2 to n do
    if f[i,2]=1 then
    begin
        x:=getfather(f[i,1]);
        y:=getfather(i);
        if x<>y then fa[y]:=x;
    end;
    for i:=2 to n do ff[i,0]:=f[i,1];
    cc[0]:=1;
    for i:=1 to 17 do cc[i]:=cc[i-1]*2;
    make_ff;
    for i:=1 to q do
    begin
        read(x);
        if x=1 then
        begin
            readln(x,y,z);
            x1:=x;
            y1:=y;
            if deep[x]<deep[y] then
            begin
                t1:=x;
                x:=y;
                y:=t1;
            end;
            t1:=deep[x]-deep[y];
            t2:=0;
            while t1>0 do
            begin
                if t1 mod 2=1 then x:=ff[x,t2];
                inc(t2);
                t1:=t1 div 2;
            end;
            t1:=deep[x];
            for j:=17 downto 0 do
            if ff[x,j]<>ff[y,j] then
            begin
                x:=ff[x,j];
                y:=ff[y,j];
                t1:=t1-cc[j];
            end;
            if x<>y then dec(t1);
            x:=x1;
            while (deep[x]>t1) and (z>0) do
            begin
                if f[x,2]=1 then
                begin
                    x:=getfather(f[x,1]);
                    if deep[x]<=t1 then break;
                end else
                begin
                    z:=z div f[x,2];
                    x:=f[x,1];
                end;
            end;
            x:=y1;
            while (deep[x]>t1) and (z>0) do
            begin
                if f[x,2]=1 then
                begin
                    x:=getfather(f[x,1]);
                    if deep[x]<=t1 then break;
                end else
                begin
                    z:=z div f[x,2];
                    x:=f[x,1];
                end;
            end;
            writeln(z);
        end else
        begin
            readln(x,y);
            if f[p[x,2],1]=p[x,1] then
            begin
                f[p[x,2],2]:=y;
                t1:=p[x,2];
                t2:=p[x,1];
            end
            else
            begin
                f[p[x,1],2]:=y;
                t1:=p[x,1];
                t2:=p[x,2];
            end;
            if y=1 then
                fa[t1]:=t2;
        end;
    end;
    close(input); close(output);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值