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
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 }

 

 

 

 

 

 

 

 

 

 

 

 

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/p/3300251.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞