这是一个比较经典的动态树模型,对于理解动态树还是很管用的~
动态树就是很多splay组成的,每颗splay维护的是一条树链,splay之间用fa[]相连,如fa[x]=y表示以x为根的splay树的父亲是y,但是y的两个儿子(son[y][0]和son[y][1])中没有一个是x
相对的,splay之间的父子关系也是通过fa[]和son[][]来维护的,不同的是,如果fa[x]=y,则必有son[y][0]或者son[y][1]等于x,这个一定要想明白!
对于无向图,就是先bfs建树,此时每一个点都是一颗splay,因为对于任意fa[x]=y,son[y][0]和son[y][1]一定不是x
isroot(x):判断x是否为其所在splay树的根(依据上述关系)
splay(x):将x旋转为其所在的splay树的根
access(x):将x到root(即原树的根,不同于x所在的splay树的根)的路径变成实边,注意理解函数中y的意义
querysum(x,y)/querymax(x,y):求x到y的路径上的点权和/最大点权,实质就是求包含x和y的splay的lca
先access(x),此时从x到root变成一条实边,即在同一颗splay树种(此时x向下的实边已经断开了,也就是说x是其所在splay树种深度最大的点了)
再access(y),此时从y到root变成一条实边,返回值就是lca(画个图挺好理解的,这里一定要想明白!)
其实动态树的精髓是link和cut,要加上旋转标记,就是将一颗splay树维护的链全部反向
以上是我的理解,应该是对的。。。嘿嘿。
代码觉得挺简单易懂的,可以看一下~
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 7 #define N 500000 8 #define INF 0x7f7f7f7f 9 10 using namespace std; 11 //http://www.cnblogs.com/proverbs/archive/2013/01/04/2845053.html 12 int n,m,cnt; 13 bool vis[N]; 14 int to[N],next[N],head[N],q[N]; 15 int fa[N],son[N][2],mx[N],val[N],sum[N]; 16 17 inline void pushup(int x) 18 { 19 if(!x) return; 20 mx[x]=max(val[x],max(mx[son[x][0]],mx[son[x][1]])); 21 sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x]; 22 } 23 24 inline bool isroot(int x) 25 { 26 return son[fa[x]][0]!=x&&son[fa[x]][1]!=x; 27 } 28 29 inline void link(int x,int y,int c) 30 { 31 fa[x]=y; son[y][c]=x; 32 } 33 34 inline void rotate(int x,int c) 35 { 36 int y=fa[x]; 37 if(!isroot(y)) link(x,fa[y],son[fa[y]][1]==y); 38 else fa[x]=fa[y]; 39 link(son[x][!c],y,c); 40 link(y,x,!c); 41 pushup(y); 42 } 43 44 inline void splay(int x) 45 { 46 while(!isroot(x)) 47 { 48 int y=fa[x]; 49 int cy=(son[fa[y]][1]==y),cx=(son[y][1]==x); 50 if(isroot(y)) rotate(x,cx); 51 else 52 { 53 if(cx==cy) rotate(y,cy); 54 else rotate(x,cx); 55 rotate(x,cy); 56 } 57 } 58 pushup(x); 59 } 60 61 inline int access(int x) 62 { 63 int y; 64 for(y=0;x;y=x,x=fa[x]) 65 { 66 splay(x); 67 son[x][1]=y; 68 pushup(x); 69 } 70 return y; 71 } 72 73 inline int querysum(int x,int y) 74 { 75 access(x); 76 int lca=access(y); 77 splay(x); 78 if(lca==x) return val[lca]+sum[son[lca][1]]; 79 else return val[lca]+sum[son[lca][1]]+sum[x]; 80 } 81 82 inline int querymax(int x,int y) 83 { 84 access(x); 85 int lca=access(y); 86 splay(x); 87 if(lca==x) return max(val[lca],mx[son[lca][1]]); 88 else return max(val[lca],max(mx[son[lca][1]],mx[x])); 89 } 90 91 inline void change(int x,int w) 92 { 93 //access(x); 94 splay(x); val[x]=w; pushup(x); 95 } 96 97 inline void add(int u,int v) 98 { 99 to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++; 100 } 101 102 inline void bfs() 103 { 104 memset(vis,0,sizeof vis); 105 vis[1]=true; q[1]=1; 106 int h=1,t=2,sta; 107 while(h<t) 108 { 109 sta=q[h++]; 110 for(int i=head[sta];~i;i=next[i]) 111 if(!vis[to[i]]) 112 { 113 fa[to[i]]=sta; 114 vis[to[i]]=true; 115 q[t++]=to[i]; 116 } 117 } 118 } 119 120 inline void go() 121 { 122 memset(head,-1,sizeof head); cnt=0; 123 memset(son,0,sizeof son); 124 memset(fa,0,sizeof fa); 125 mx[0]=-INF; 126 scanf("%d",&n); 127 for(int i=1,a,b;i<n;i++) 128 { 129 scanf("%d%d",&a,&b); 130 add(a,b); add(b,a); 131 } 132 for(int i=1;i<=n;i++) scanf("%d",&val[i]); 133 bfs(); 134 scanf("%d",&m); 135 char str[10]; int a,b; 136 while(m--) 137 { 138 scanf("%s",str); 139 scanf("%d%d",&a,&b); 140 if(str[1]=='H') change(a,b); 141 else if(str[1]=='S') printf("%d\n",querysum(a,b)); 142 else printf("%d\n",querymax(a,b)); 143 } 144 } 145 146 int main() 147 { 148 go(); 149 return 0; 150 }