1. 程式人生 > >P2590 [ZJOI2008]樹的統計(LCT)

P2590 [ZJOI2008]樹的統計(LCT)

ota har namespace while 說明 play dash logs 輸入

P2590 [ZJOI2008]樹的統計

題目描述

一棵樹上有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 }

P2590 [ZJOI2008]樹的統計(LCT)