HDU 4010 Query on The Trees (動態樹)


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
 

 

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 }

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM