一般适用于对于树的区间查询与修改。
几个定义:
树链:树上两点之间的路径。
剖分:将树上的边划分为轻边和重边。
重儿子:在 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; }