Query on The Trees
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 1527 Accepted Submission(s): 747
Problem Description
We have met so many problems on the tree, so today we will have a query problem on a set of trees.
There are N nodes, each node will have a unique weight Wi. We will have four kinds of operations on it and you should solve them efficiently. Wish you have fun!
There are N nodes, each node will have a unique weight Wi. We will have four kinds of operations on it and you should solve them efficiently. Wish you have fun!
Input
There are multiple test cases in our dataset.
For each case, the first line contains only one integer N.(1 ≤ N ≤ 300000) The next N‐1 lines each contains two integers x, y which means there is an edge between them. It also means we will give you one tree initially.
The next line will contains N integers which means the weight Wi of each node. (0 ≤ Wi ≤ 3000)
The next line will contains an integer Q. (1 ≤ Q ≤ 300000) The next Q lines will start with an integer 1, 2, 3 or 4 means the kind of this operation.
1. Given two integer x, y, you should make a new edge between these two node x and y. So after this operation, two trees will be connected to a new one.
2. Given two integer x, y, you should find the tree in the tree set who contain node x, and you should make the node x be the root of this tree, and then you should cut the edge between node y and its parent. So after this operation, a tree will be separate into two parts.
3. Given three integer w, x, y, for the x, y and all nodes between the path from x to y, you should increase their weight by w.
4. Given two integer x, y, you should check the node weights on the path between x and y, and you should output the maximum weight on it.
For each case, the first line contains only one integer N.(1 ≤ N ≤ 300000) The next N‐1 lines each contains two integers x, y which means there is an edge between them. It also means we will give you one tree initially.
The next line will contains N integers which means the weight Wi of each node. (0 ≤ Wi ≤ 3000)
The next line will contains an integer Q. (1 ≤ Q ≤ 300000) The next Q lines will start with an integer 1, 2, 3 or 4 means the kind of this operation.
1. Given two integer x, y, you should make a new edge between these two node x and y. So after this operation, two trees will be connected to a new one.
2. Given two integer x, y, you should find the tree in the tree set who contain node x, and you should make the node x be the root of this tree, and then you should cut the edge between node y and its parent. So after this operation, a tree will be separate into two parts.
3. Given three integer w, x, y, for the x, y and all nodes between the path from x to y, you should increase their weight by w.
4. Given two integer x, y, you should check the node weights on the path between x and y, and you should output the maximum weight on it.
Output
For each query you should output the correct answer of it. If you find this query is an illegal operation, you should output ‐1.
You should output a blank line after each test case.
You should output a blank line after each test case.
Sample Input
5 1 2 2 4 2 5 1 3 1 2 3 4 5 6 4 2 3 2 1 2 4 2 3 1 3 5 3 2 1 4 4 1 4
Sample Output
3 -1 7
Hint
We define the illegal situation of different operations: In first operation: if node x and y belong to a same tree, we think it's illegal. In second operation: if x = y or x and y not belong to a same tree, we think it's illegal. In third operation: if x and y not belong to a same tree, we think it's illegal. In fourth operation: if x and y not belong to a same tree, we think it's illegal.
Source
Recommend
lcy
動態樹入門。
解釋看代碼:
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-9-4 0:13:15 4 File Name :HDU4010.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 //動態維護一組森林,要求支持一下操作: 21 //link(a,b) : 如果a,b不在同一顆子樹中,則通過在a,b之間連邊的方式,連接這兩顆子樹 22 //cut(a,b) : 如果a,b在同一顆子樹中,且a!=b,則將a視為這顆子樹的根以后,切斷b與其父親結點的連接 23 //ADD(a,b,w): 如果a,b在同一顆子樹中,則將a,b之間路徑上所有點的點權增加w 24 //query(a,b): 如果a,b在同一顆子樹中,返回a,b之間路徑上點權的最大值 25 const int MAXN = 300010; 26 int ch[MAXN][2],pre[MAXN],key[MAXN]; 27 int add[MAXN],rev[MAXN],Max[MAXN]; 28 bool rt[MAXN]; 29 30 void Update_Add(int r,int d) 31 { 32 if(!r)return; 33 key[r] += d; 34 add[r] += d; 35 Max[r] += d; 36 } 37 void Update_Rev(int r) 38 { 39 if(!r)return; 40 swap(ch[r][0],ch[r][1]); 41 rev[r] ^= 1; 42 } 43 void push_down(int r) 44 { 45 if(add[r]) 46 { 47 Update_Add(ch[r][0],add[r]); 48 Update_Add(ch[r][1],add[r]); 49 add[r] = 0; 50 } 51 if(rev[r]) 52 { 53 Update_Rev(ch[r][0]); 54 Update_Rev(ch[r][1]); 55 rev[r] = 0; 56 } 57 } 58 void push_up(int r) 59 { 60 Max[r] = max(max(Max[ch[r][0]],Max[ch[r][1]]),key[r]); 61 } 62 void Rotate(int x) 63 { 64 int y = pre[x], kind = ch[y][1]==x; 65 ch[y][kind] = ch[x][!kind]; 66 pre[ch[y][kind]] = y; 67 pre[x] = pre[y]; 68 pre[y] = x; 69 ch[x][!kind] = y; 70 if(rt[y]) 71 rt[y] = false, rt[x] = true; 72 else 73 ch[pre[x]][ch[pre[x]][1]==y] = x; 74 push_up(y); 75 } 76 //P函數先將根結點到r的路徑上所有的結點的標記逐級下放 77 void P(int r) 78 { 79 if(!rt[r])P(pre[r]); 80 push_down(r); 81 } 82 void Splay(int r) 83 { 84 P(r); 85 while( !rt[r] ) 86 { 87 int f = pre[r], ff = pre[f]; 88 if(rt[f]) 89 Rotate(r); 90 else if( (ch[ff][1]==f)==(ch[f][1]==r) ) 91 Rotate(f), Rotate(r); 92 else 93 Rotate(r), Rotate(r); 94 } 95 push_up(r); 96 } 97 int Access(int x) 98 { 99 int y = 0; 100 for( ; x ; x = pre[y=x]) 101 { 102 Splay(x); 103 rt[ch[x][1]] = true, rt[ch[x][1]=y] = false; 104 push_up(x); 105 } 106 return y; 107 } 108 //判斷是否是同根(真實的樹,非splay) 109 bool judge(int u,int v) 110 { 111 while(pre[u]) u = pre[u]; 112 while(pre[v]) v = pre[v]; 113 return u == v; 114 } 115 //使r成為它所在的樹的根 116 void mroot(int r) 117 { 118 Access(r); 119 Splay(r); 120 Update_Rev(r); 121 } 122 //調用后u是原來u和v的lca,v和ch[u][1]分別存着lca的2個兒子 123 //(原來u和v所在的2顆子樹) 124 void lca(int &u,int &v) 125 { 126 Access(v), v = 0; 127 while(u) 128 { 129 Splay(u); 130 if(!pre[u])return; 131 rt[ch[u][1]] = true; 132 rt[ch[u][1]=v] = false; 133 push_up(u); 134 u = pre[v = u]; 135 } 136 } 137 void link(int u,int v) 138 { 139 if(judge(u,v)) 140 { 141 puts("-1"); 142 return; 143 } 144 mroot(u); 145 pre[u] = v; 146 } 147 //使u成為u所在樹的根,並且v和它父親的邊斷開 148 void cut(int u,int v) 149 { 150 if(u == v || !judge(u,v)) 151 { 152 puts("-1"); 153 return; 154 } 155 mroot(u); 156 Splay(v); 157 pre[ch[v][0]] = pre[v]; 158 pre[v] = 0; 159 rt[ch[v][0]] = true; 160 ch[v][0] = 0; 161 push_up(v); 162 } 163 void ADD(int u,int v,int w) 164 { 165 if(!judge(u,v)) 166 { 167 puts("-1"); 168 return; 169 } 170 lca(u,v); 171 Update_Add(ch[u][1],w); 172 Update_Add(v,w); 173 key[u] += w; 174 push_up(u); 175 } 176 void query(int u,int v) 177 { 178 if(!judge(u,v)) 179 { 180 puts("-1"); 181 return; 182 } 183 lca(u,v); 184 printf("%d\n",max(max(Max[v],Max[ch[u][1]]),key[u])); 185 } 186 187 struct Edge 188 { 189 int to,next; 190 }edge[MAXN*2]; 191 int head[MAXN],tot; 192 void addedge(int u,int v) 193 { 194 edge[tot].to = v; 195 edge[tot].next = head[u]; 196 head[u] = tot++; 197 } 198 void dfs(int u) 199 { 200 for(int i = head[u];i != -1; i = edge[i].next) 201 { 202 int v = edge[i].to; 203 if(pre[v] != 0)continue; 204 pre[v] = u; 205 dfs(v); 206 } 207 } 208 209 int main() 210 { 211 //freopen("in.txt","r",stdin); 212 //freopen("out.txt","w",stdout); 213 int n,q,u,v; 214 while(scanf("%d",&n) == 1) 215 { 216 tot = 0; 217 for(int i = 0;i <= n;i++) 218 { 219 head[i] = -1; 220 pre[i] = 0; 221 ch[i][0] = ch[i][1] = 0; 222 rev[i] = 0; 223 add[i] = 0; 224 rt[i] = true; 225 } 226 Max[0] = -2000000000; 227 for(int i = 1;i < n;i++) 228 { 229 scanf("%d%d",&u,&v); 230 addedge(u,v); 231 addedge(v,u); 232 } 233 for(int i = 1;i <= n;i++) 234 { 235 scanf("%d",&key[i]); 236 Max[i] = key[i]; 237 } 238 scanf("%d",&q); 239 pre[1] = -1; 240 dfs(1); 241 pre[1] = 0; 242 int op; 243 while(q--) 244 { 245 scanf("%d",&op); 246 if(op == 1) 247 { 248 int x,y; 249 scanf("%d%d",&x,&y); 250 link(x,y); 251 } 252 else if(op == 2) 253 { 254 int x,y; 255 scanf("%d%d",&x,&y); 256 cut(x,y); 257 } 258 else if(op == 3) 259 { 260 int w,x,y; 261 scanf("%d%d%d",&w,&x,&y); 262 ADD(x,y,w); 263 } 264 else 265 { 266 int x,y; 267 scanf("%d%d",&x,&y); 268 query(x,y); 269 } 270 } 271 printf("\n"); 272 } 273 return 0; 274 }