一般适用于对于树的区间查询与修改。
几个定义:
树链:树上两点之间的路径。
剖分:将树上的边划分为轻边和重边。
重儿子:在 u 的儿子节点中,siz最大的那个节点即为 u 的重儿子。(若存在多个,则任选一个)
轻儿子:除重儿子之外的所有儿子节点均为轻儿子。
重边:父节点与重儿子之间的连边。
轻边:父节点与轻儿子之间的连边。
重链:由重边首尾相连组成的路径。
操作之前需要通过dfs初始化一些信息,fa[] , son[] , siz[] , top[] , dot_site[] , dep[] ,seg[]。
fa[s] :s 的父节点。根节点无意义。
son[s] :s的重儿子。叶子节点无意义。
dep[s] :s的深度。
top[s] :s所在链的深度最小的点。
siz[s] :以s为根节点的子树上的节点总数。
dot_site[s] , s 在dfs时的时间戳。
seg为dfs时的次序。
如图所示:
途中粗线即为重边,细线即为轻边。
则图中重链有 :1. (1 -> 4 -> 7 -> 10) 2. (2 -> 12) 3. ( 6->9 ) 。
图中点旁边的数字即为相应的点的 top[] 。
为了保证重链上的点在 dfs 时连续,则在dfs时要优先对其重儿子进行dfs(显然除叶子节点外的所有节点均存在重儿子)。
则dfs完成后 seg存储的内容为 { 1,4,7,10,11,6,9,5,2,12 , 3}。
然后对 seg 建立线段树,继而对线段树进行查询和更新。
因为任意两点间的重链和轻边的数量均不超过 log(n),n 两点之间的边的条数,所以在对任意一段路径查询和更新时,其对线段
树的操作次数不会超过2*log(n)。(所示树链剖分的一个性质吧)。
以查询为例。
while(1)
{
设 fu = top[u] , fv = top[v]。
1. 当fu != fv(设 dep[fu] > dep[fv] ) 时,查询seg[] 的子区间 [ dot_site[fu] , dot_site[u] ]上的最值 , u = fa[fu] .
2. 当 fu == fv 时,u,v在一条重链上,若 u == v,查询结束,否则查询 [dot_site[ u ] ,dot_site[ v ] ] (设dep[u] < dep[v]),查询结束。
}
心情有点小低谷。。。墨迹了好久才写完。。。离别的前奏总是这样伤感。
___________ Updata 3.28_____________
总算有一份还算满意的代码了。。
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>
#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-6)
#define LL long long
#define ULL unsigned long long int
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 1000000007
using namespace std;
const int MAXN = 30010;
struct N
{
int u,v,next;
}edge[MAXN*2];
int head[MAXN];
int Top;
void Link(int u,int v)
{
edge[Top].u = u , edge[Top].v = v , edge[Top].next = head[u] , head[u] = Top++;
}
int Top_E;
int siz[MAXN],fa[MAXN],son[MAXN],dot_site[MAXN],dep[MAXN],top[MAXN],val[MAXN],seg[MAXN];
void dfs1(int s,int pre,int d)
{
dep[s] = d , fa[s] = pre , siz[s] = 1 , son[s] = -1;
for(int p = head[s] ; p != -1; p = edge[p].next)
{
if(edge[p].v != pre)
{
dfs1(edge[p].v,s,d+1);
if(son[s] == -1 || siz[son[s]] < siz[edge[p].v])
son[s] = edge[p].v;
siz[s] += siz[edge[p].v] + 1;
}
}
}
void dfs2(int s,int pre,int T)
{
top[s] = T , dot_site[s] = ++Top_E , seg[Top_E] = s ;
if(son[s] == -1)
return ;
dfs2(son[s],s,T);
for(int p = head[s] ; p != -1; p = edge[p].next)
{
if(edge[p].v != son[s] && edge[p].v != pre)
{
dfs2(edge[p].v,s,edge[p].v);
}
}
}
struct ST
{
int Max,Sum;
}st[MAXN*4];
void Init(int site, int l , int r)
{
if(l == r)
{
st[site].Max = val[seg[l]] , st[site].Sum = val[seg[r]];
return ;
}
int mid = (l+r)>>1;
Init(site<<1,l,mid);
Init(site<<1|1,mid+1,r);
st[site].Sum = st[site<<1].Sum + st[site<<1|1].Sum;
st[site].Max = max(st[site<<1].Max , st[site<<1|1].Max);
}
void Updata(int site,int l,int r,int x)
{
if(l == r && r == x)
{
st[site].Max = val[seg[l]] , st[site].Sum = val[seg[r]];
return ;
}
int mid = (l+r)>>1;
if(x <= mid)
Updata(site<<1,l,mid,x);
else
Updata(site<<1|1,mid+1,r,x);
st[site].Sum = st[site<<1].Sum + st[site<<1|1].Sum;
st[site].Max = max(st[site<<1].Max , st[site<<1|1].Max);
}
ST Query(int site,int L,int R,int l,int r)
{
if(L == l && R == r)
{
return st[site];
}
int mid = (L+R)>>1;
if(r <= mid)
return Query(site<<1,L,mid,l,r);
else if(mid < l)
return Query(site<<1|1,mid+1,R,l,r);
ST t1,t2,t3;
t1 = Query(site<<1,L,mid,l,mid);
t2 = Query(site<<1|1,mid+1,R,mid+1,r);
t3.Max = max(t1.Max,t2.Max);
t3.Sum = t1.Sum + t2.Sum;
return t3;
}
int main()
{
//freopen("C.in","r",stdin);
//freopen("C.out","w",stdout);
char s[20];
int n,i;
int u,v;
while(scanf("%d",&n) != EOF)
{
memset(head,-1,sizeof(int)*(n+2));
Top = 0;
for( i= 1;i < n; ++i)
{
scanf("%d %d",&u,&v);
Link(u,v);
Link(v,u);
}
for(i = 1;i <= n; ++i)
{
scanf("%d",&val[i]);
}
dfs1(1,-1,1);
Top_E = 0;
dfs2(1,-1,1);
Init(1,1,Top_E);
int q;
scanf("%d",&q);
while(q--)
{
scanf("%*c%s %d %d",s,&u,&v);
if(s[1] == 'H')
{
val[u] = v;
Updata(1,1,Top_E,dot_site[u]);
}
else
{
ST anw,temp;
anw.Sum = 0;
anw.Max = val[u];
int fu = top[u],fv = top[v];
while(fu != fv)
{
if(dep[fu] < dep[fv])
swap(u,v),swap(fu,fv);
temp = Query(1,1,Top_E,dot_site[fu],dot_site[u]);
anw.Sum += temp.Sum;
anw.Max = max(anw.Max,temp.Max);
u = fa[fu];
fu = top[u];
}
if(dep[u] < dep[v])
swap(u,v);
temp = Query(1,1,Top_E,dot_site[v],dot_site[u]);
anw.Sum += temp.Sum;
anw.Max = max(anw.Max,temp.Max);
if(s[1] == 'M')
printf("%d\n",anw.Max);
else if(s[1] == 'S')
printf("%d\n",anw.Sum);
}
}
}
return 0;
}