将一颗树划分成几条不相交的链,让每一节点都存在且仅存在于一条链中,这样我们就得到了数个线性的结构,然后可以用线段树等数据结构去维护这个整体。
其实就是一个将数据结构推广至树上的方法。
可以用来求解比如查询节点 x 到节点 y 的路径的所有点的 max,sum 等等
一般我们可以使用轻重边剖分。
每个节点最多只有一条重边连接他与他的子节点。
假如以节点 u 的子节点 v 为根的子树的 SIZE 最大,那么我们就取边 (u,v) 为节点u的重边。
其他边为轻边
从根到某一点的路径上轻边的个数都不大于 log2(n) 。
这个很好想,首先我们对于一颗二叉树的根节点 r 与假设节点 k ,显然有 k 所在的以 a 为根的子树 size(a) 越大,可能的轻边就越多。但要让 (r,a) 这条边为轻边,那 size(a) 就必须小于另外一个子树。所以 size(a) 最大只能取 (size(r)−1)/2 。这样递归的做下去,那就是每次/2,就是 log2(n) 了。
对于k叉树,也是相同的,最大取 (size(r)−1)/2
顾名思义,重边连成的一条链。
其实只要你愿意,完全可以乱分链。 只不过按轻重边划分的话呢,就有了那个很好的轻边性质,保证我们的算法复杂度不会太高。
1.找出重边。
2.将重边相连得重链,头尾相连按序放入数据结构。
这里有一个问题,就是叶子节点怎么办,可能不会被重边所连。
那我们就直接当他是链顶,放入线段树。
3.维护求值。
在树上有两个点 u,v ,求u到v路径上的最大点权。
首先我们找到各自链顶 top(u),top(v) 。
假如 top(u) 比 top(v) 深度更大,那么我们可以更新路径 (u,top(u)) ,因为是一段重链,所以在线段树中应该是相连的,所以直接查询O( log2(n) )。
然后将u跳到father(top(u)),重复上述步骤,直到跳到了同一条重链上为止。即 top(u)=top(v) ,然后再更新路径 (u,v) 。
修改同理,将查询换为区间修改即可。
每跳一次重边就相当于跳过了一条轻边。 而且轻边有一个很优美的性质。
从根到某一点的路径上轻边的个数都不大于 log2(n) 。
我们可以保证最多有 log2(n) 条重链(每条轻边都会断开重链),每一次修改&查询复杂度就是 log2(n)∗数据结构 。
type
node=record
m,s:longint;
end;
var
t:array[1..120000] of node;
sum,tot,u,v,a,b,i,j,k,n,m,q:longint;
s:char;
re,cl:node;
dfp,head,next,father,dep,loc,bl,top,size,w,e,h:array[0..60000] of longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure new(a,b:longint);
begin
inc(tot);
e[tot]:=b;
next[tot]:=head[a];
head[a]:=tot;
end;
procedure update(x:longint);
begin
t[x].s:=t[x*2].s+t[x*2+1].s;
t[x].m:=max(t[x*2].m,t[x*2+1].m);
end;
procedure swap(var a,b:longint);
var t:longint;
begin
t:=a; a:=b; b:=t;
end;
procedure dfs_h(x,fa,d:longint); {找重边}
var k:longint;
begin
father[x]:=fa;
dep[x]:=d;
inc(size[x]);
k:=head[x];
while k<>0 do
begin
if e[k]<>fa then
begin
dfs_h(e[k],x,d+1);
inc(size[x],size[e[k]]);
if size[e[k]]>size[h[x]] then h[x]:=e[k];
end;
k:=next[k];
end;
end;
procedure dfs(x,fa,topp:longint); {连重链一起放入线段树,其他随便放}
var k:longint;
begin
inc(loc[0]);
loc[loc[0]]:=x;
dfp[x]:=loc[0];
top[x]:=topp;
if h[x]=0 then exit();
dfs(h[x],x,topp);
k:=head[x];
while k<>0 do
begin
if (e[k]<>fa)and(e[k]<>h[x]) then dfs(e[k],x,e[k]);
k:=next[k];
end;
end;
procedure build(x,l,r:longint);
begin
if l=r then
begin
t[x].s:=w[loc[l]];
t[x].m:=w[loc[l]];
exit();
end;
build(x*2,l,(l+r) shr 1);
build(x*2+1,(l+r) shr 1+1,r);
update(x);
end;
procedure change(x,l,r,tg,v:longint);
var mid:longint;
begin
if (l>tg)or(r<tg) then exit();
if (l=r)and(l=tg) then
begin
t[x].s:=v; t[x].m:=v;
exit();
end;
mid:=(l+r) shr 1;
change(x*2,l,mid,tg,v);
change(x*2+1,mid+1,r,tg,v);
update(x);
end;
procedure query(x,l,r,ql,qr:longint);
var mid:longint;
begin
if (l>qr)or(r<ql) then exit();
if (ql<=l)and(qr>=r) then
begin
inc(re.s,t[x].s);
if t[x].m>re.m then re.m:=t[x].m;
exit();
end;
mid:=(l+r) shr 1;
query(x*2,l,mid,ql,qr);
query(x*2+1,mid+1,r,ql,qr);
end;
procedure find(u,v:longint); {链上查询操作}
var big,small:longint;
begin
re:=cl;
while top[u]<>top[v] do
begin
if dep[top[u]]<dep[top[v]] then swap(u,v);
query(1,1,n,dfp[top[u]],dfp[u]);
u:=father[top[u]];
end;
if dfp[u]>dfp[v] then swap(u,v);
query(1,1,n,dfp[u],dfp[v]);
end;
procedure init;
begin
readln(n);
for i:=1 to n-1 do
begin
readln(a,b);
new(a,b);
new(b,a);
end;
for i:=1 to n do
begin
read(w[i]);
end;
readln(q);
dfs_h(1,0,1);
dfs(1,0,1);
build(1,1,n);
cl.m:=-maxlongint;
end;
procedure main;
begin
for i:=1 to q do
begin
read(s);
if s='C' then
begin
while s<>' ' do read(s);
readln(u,v);
w[u]:=v;
change(1,1,n,dfp[u],v);
end else
begin
inc(sum);
read(s,s,s);
readln(u,v);
find(u,v);
if s='X' then writeln(re.m) else writeln(re.s);
end;
end;
end;
begin
init();
main();
end.