P2590 [ZJOI2008]树的统计(LCT)
题目描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
输入输出格式
输入格式:
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来一行n个整数,第i个整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
输出格式:
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
输入输出样例
输入样例#1: 复制
4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2 3 QSUM 3 4 QSUM 2 1 CHANGE 1 5 QMAX 3 4 CHANGE 3 6 QMAX 3 4 QMAX 2 4 QSUM 3 4
输出样例#1: 复制
4 1 2 2 10 6 5 6 5 16
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
code
树链剖分1000ms左右,动态树4000ms多,不过动态树比树链剖分好写一点。
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 const int N = 50100; 7 8 int val[N],fa[N],ch[N][2],rev[N],sum[N],mx[N],st[N],top; 9 struct Edge{ 10 int to,nxt; 11 }e[N<<1]; 12 int head[N],tot; 13 14 inline void add_edge(int u,int v) { 15 e[++tot].to = v,e[tot].nxt = head[u],head[u] = tot; 16 } 17 void pushup(int x) { 18 sum[x] = sum[ch[x][1]] + sum[ch[x][0]] + val[x]; 19 mx[x] = max(max(mx[ch[x][1]],mx[ch[x][0]]),val[x]); 20 } 21 void pushdown(int x) { 22 int l = ch[x][0],r = ch[x][1]; 23 if (rev[x]) { 24 rev[l] ^= 1;rev[r] ^= 1; 25 swap(ch[x][0],ch[x][1]); 26 rev[x] ^= 1; 27 } 28 } 29 bool isroot(int x) { 30 return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; 31 } 32 int son(int x) { 33 return ch[fa[x]][1]==x; 34 } 35 void rotate(int x) { 36 int y = fa[x],z = fa[y],b = son(x),c = son(y),a = ch[x][!b]; 37 if (!isroot(y)) ch[z][c] = x;fa[x] = z; 38 ch[x][!b] = y;fa[y] = x; 39 ch[y][b] = a;if (a) fa[a] = y; 40 pushup(y);pushup(x); 41 } 42 void splay(int x) { 43 top = 0;st[++top] = x; 44 for (int i=x; !isroot(i); i=fa[i]) st[++top] = fa[i]; 45 while (top) pushdown(st[top--]); 46 while (!isroot(x)) { 47 int y = fa[x]; 48 if (!isroot(y)) { 49 if (son(x)==son(y)) rotate(y); 50 else rotate(x); 51 } 52 rotate(x); 53 } 54 } 55 void access(int x) { 56 for (int t=0; x; t=x,x=fa[x]) { 57 splay(x);ch[x][1] = t;pushup(x); 58 } 59 } 60 void makeroot(int x) { 61 access(x); 62 splay(x); 63 rev[x] ^= 1; 64 } 65 void update(int x,int y) { 66 makeroot(x);val[x] = y;pushup(x); 67 } 68 int query_max(int x,int y) { 69 makeroot(x);access(y);splay(y); 70 return mx[y]; // - 71 } 72 int query_sum(int x,int y) { 73 makeroot(x);access(y);splay(y); 74 return sum[y]; // - 75 } 76 void dfs(int u) { 77 for (int i=head[u]; i; i=e[i].nxt) { 78 int v = e[i].to; 79 if (v==fa[u]) continue; 80 fa[v] = u; 81 dfs(v); 82 } 83 } 84 int main() { 85 int n,q,x,y; 86 char opt[20]; 87 mx[0] = -1e9; // - 88 scanf("%d",&n); 89 for (int a,b,i=1; i<n; ++i) { 90 scanf("%d%d",&a,&b); 91 add_edge(a,b);add_edge(b,a); 92 } 93 for (int i=1; i<=n; ++i) scanf("%d",&val[i]); 94 dfs(1); 95 scanf("%d",&q); 96 while (q--) { 97 scanf("%s%d%d",opt,&x,&y); 98 if (opt[1]=='H') update(x,y); 99 else if (opt[1]=='M') printf("%d\n",query_max(x,y)); 100 else printf("%d\n",query_sum(x,y)); 101 } 102 return 0; 103 }