题目大意:
给你一个无根树,要求满足两个操作:
1.查询两个点的距离;
2.修改某一条边的权值。
正确做法是用线段树维护一个DFS序列,因为想温习下动态树所以很NC的编了个动态树。
较之之前的动态树,这里多得操作是查询两个点的距离。
由于死循环TLE了1次之后AC。
很无解的,常数巨大的动态树竟然也可以超过绝大多数的线段树:
procedure left(i:longint);
begin
j:=r[i];r[i]:=l[j];fa[r[i]]:=i;;l[j]:=i;
fa[j]:=fa[i];fa[i]:=j;
root[j]:=root[i];root[i]:=false;
s[i]:=s[l[i]]+s[r[i]]+w[i];
s[j]:=s[l[j]]+s[r[j]]+w[j];
if i=l[fa[j]] then l[fa[j]]:=j else
if i=r[fa[j]] then r[fa[j]]:=j;
i:=j;
end;
procedure right(i:longint);
begin
j:=l[i];l[i]:=r[j];fa[l[i]]:=i;r[j]:=i;
fa[j]:=fa[i];fa[i]:=j;
root[j]:=root[i];root[i]:=false;
s[i]:=s[l[i]]+s[r[i]]+w[i];
s[j]:=s[l[j]]+s[r[j]]+w[j];
if i=l[fa[j]] then l[fa[j]]:=j else
if i=r[fa[j]] then r[fa[j]]:=j;
i:=j;
end;
procedure cut(i:longint);
begin
while not root[i] do
if l[fa[i]]=i then right(fa[i]) else left(fa[i]);
tmp:=s[l[i]];root[l[i]]:=true;
dec(s[i],tmp);l[i]:=0;
end;
procedure access(i:longint);
begin
cut(i);
while fa[i]<>0 do begin
cut(fa[i]);root[fa[i]]:=false;
inc(tmp,s[i]);
fa[r[i]]:=fa[i];j:=fa[i];
l[fa[i]]:=r[i];r[i]:=fa[i];
fa[i]:=fa[j];fa[j]:=i;
s[j]:=s[l[j]]+s[r[j]]+w[j];
s[i]:=s[l[i]]+s[r[i]]+w[i];
end;
end;
procedure link(a,b,cc:longint);
begin inc(t);next[t]:=d[a];d[a]:=t;p[t]:=b;c[t]:=cc end;
procedure dfs(i,f:longint);var k:longint;
begin
root[i]:=true;fa[i]:=f;k:=d[i];
while k<>0 do begin
if p[k]<>f then begin
w[p[k]]:=c[k];s[p[k]]:=c[k];
dfs(p[k],i);e[(k+1)div 2]:=p[k];
end;
k:=next[k];
end;
end;
begin
readln(n,q,ss);
for i:=1 to n-1 do begin
readln(a,b,cc);
link(a,b,cc);link(b,a,cc);
end;
dfs(ss,0);
for i:=1 to q do begin
read(a);
if a=1 then begin
readln(b,cc);j:=e[b];
cut(j);inc(s[j],cc-w[j]);w[j]:=cc;
end else begin
readln(b);
access(ss);access(b);
ss:=b;writeln(tmp);
end;
end;
end.