Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 1527 Accepted Submission(s): 747
动态树入门。
解释看代码:
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 }