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!
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.
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.
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
The 36th ACM/ICPC Asia Regional Dalian Site —— Online Contest
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 }