HDU 3966 Aragorn's Story 动态树 树链剖分
Aragorn's Story
Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
【Problem Description】
Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the enemy has N camps out of his kingdom and M edges connect them. It is guaranteed that for any two camps, there is one and only one path connect them. At first Aragorn know the number of enemies in every camp. But the enemy is cunning , they will increase or decrease the number of soldiers in camps. Every time the enemy change the number of soldiers, they will set two camps C1 and C2. Then, for C1, C2 and all camps on the path from C1 to C2, they will increase or decrease K soldiers to these camps. Now Aragorn wants to know the number of soldiers in some particular camps real-time.
【Input】
Multiple test cases, process to the end of input.
For each case, The first line contains three integers N, M, P which means there will be N(1 ≤ N ≤ 50000) camps, M(M = N-1) edges and P(1 ≤ P ≤ 100000) operations. The number of camps starts from 1.
The next line contains N integers A1, A2, ...AN(0 ≤ Ai ≤ 1000), means at first in camp-i has Ai enemies.
The next M lines contains two integers u and v for each, denotes that there is an edge connects camp-u and camp-v.
The next P lines will start with a capital letter 'I', 'D' or 'Q' for each line.
'I', followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, increase K soldiers to these camps.
'D', followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, decrease K soldiers to these camps.
'Q', followed by one integer C, which is a query and means Aragorn wants to know the number of enemies in camp C at that time.
For each case, The first line contains three integers N, M, P which means there will be N(1 ≤ N ≤ 50000) camps, M(M = N-1) edges and P(1 ≤ P ≤ 100000) operations. The number of camps starts from 1.
The next line contains N integers A1, A2, ...AN(0 ≤ Ai ≤ 1000), means at first in camp-i has Ai enemies.
The next M lines contains two integers u and v for each, denotes that there is an edge connects camp-u and camp-v.
The next P lines will start with a capital letter 'I', 'D' or 'Q' for each line.
'I', followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, increase K soldiers to these camps.
'D', followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, decrease K soldiers to these camps.
'Q', followed by one integer C, which is a query and means Aragorn wants to know the number of enemies in camp C at that time.
【Output】
For each query, you need to output the actually number of enemies in the specified camp.
【Sample Input】
3 2 5 1 2 3 2 1 2 3 I 1 3 5 Q 2 D 1 2 2 Q 1 Q 3
【Sample Output】
7 4 8
【Hint】
1.The number of enemies may be negative.
2.Huge input, be careful.
2.Huge input, be careful.
【分析】
解1:
动态维护树中路径上点的边权值。
两个点之间的路径只要找到最近公共祖先即可
主要还是找LCA这块,动态树中的这个操作是改造一下access,然后注意各标志的下放。
【教训】
跟上一次一样,也是TLE了很久,关键在于上组数据的状态量没有清理干净,重点是father和sons没有清空,结果就被坑了很久。
下次尤其注意!!
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : HDU 3966 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 #include <queue> 12 13 using namespace std; 14 15 #define MAXN (int)5E4+10 16 #define MAXM (int)1E5+10 17 18 typedef struct nod 19 { 20 int a,b; 21 } node; 22 node edge[MAXM]; 23 24 bool op(node a,node b) 25 { 26 if (a.a==b.a) return a.b<b.b; 27 else return a.a<b.a; 28 } 29 30 int sons[MAXN][2]; 31 int father[MAXN],size[MAXN],data[MAXN],change[MAXN]; 32 int start[MAXN],num[MAXN]; 33 bool root[MAXN]; 34 35 void bfs(int s) 36 { 37 queue<int>q; 38 q.push(s); 39 root[s]=true; 40 change[s]=0; 41 while(!q.empty()) 42 { 43 int now=q.front(); 44 for (int i=0;i<num[now];i++) 45 if (!root[edge[start[now]+i].b]) 46 { 47 father[edge[start[now]+i].b]=now; 48 root[edge[start[now]+i].b]=true; 49 change[edge[start[now]+i].b]=0; 50 q.push(edge[start[now]+i].b); 51 } 52 q.pop(); 53 } 54 } 55 56 void down(int x) 57 { 58 if (change[x]) 59 { 60 data[x]+=change[x]; 61 change[sons[x][0]]+=change[x]; 62 change[sons[x][1]]+=change[x]; 63 change[x]=0; 64 } 65 } 66 67 void rotate(int x,int w) //rotate(node,0/1) 68 { 69 int y=father[x]; 70 71 down(y); 72 down(x); 73 74 sons[y][!w]=sons[x][w]; 75 if (sons[x][w]) father[sons[x][w]]=y; 76 father[x]=father[y]; 77 if (father[y]&&(!root[y])) sons[father[y]][y==sons[father[y]][1]]=x; 78 sons[x][w]=y; 79 father[y]=x; 80 81 if (root[y]) 82 { 83 root[x]=true; 84 root[y]=false; 85 } 86 } 87 88 void splay__(int x) //splay(node) 89 { 90 down(x); 91 while(!root[x]) 92 { 93 if (root[father[x]]) rotate(x,x==sons[father[x]][0]); 94 else 95 { 96 int t=father[x]; 97 int w=(sons[father[t]][0]==t); 98 if (sons[t][w]==x) 99 { 100 rotate(x,!w); 101 rotate(x,w); 102 } else 103 { 104 rotate(t,w); 105 rotate(x,w); 106 } 107 } 108 } 109 } 110 111 void splay(int x) //splay(node) 112 { 113 down(x); 114 while(!root[x]) 115 { 116 if (sons[father[x]][0]==x) rotate(x,1); 117 else rotate(x,0); 118 } 119 } 120 121 void access(int v) 122 { 123 int u=v; 124 v=0; 125 while(u) 126 { 127 splay(u); 128 down(u); 129 root[sons[u][1]]=true; 130 sons[u][1]=v; 131 root[v]=false; 132 v=u; 133 u=father[u]; 134 } 135 } 136 137 void update(int v,int u,int k) 138 { 139 access(v); 140 v=0; 141 while(u) 142 { 143 splay(u); 144 if (!father[u]) 145 { 146 data[u]+=k; 147 change[v]+=k; 148 change[sons[u][1]]+=k; 149 return; 150 } 151 down(u); 152 root[sons[u][1]]=true; 153 sons[u][1]=v; 154 root[v]=false; 155 v=u; 156 u=father[u]; 157 } 158 } 159 160 int INT() { 161 char ch; 162 int res; 163 bool neg; 164 while (ch = getchar(), !isdigit(ch) && ch != '-') 165 ; 166 if (ch == '-') { 167 neg = true; 168 res = 0; 169 } else { 170 neg = false; 171 res = ch - '0'; 172 } 173 while (ch = getchar(), isdigit(ch)) 174 res = res * 10 + ch - '0'; 175 return neg ? -res : res; 176 } 177 178 char CHAR() { 179 char res; 180 while (res = getchar(), !isalpha(res)) 181 ; 182 return res; 183 } 184 185 int main() 186 { 187 freopen("3966.txt","r",stdin); 188 189 int n,m,p; 190 while(scanf("%d%d%d",&n,&m,&p)!=EOF) 191 { 192 memset(father,0,sizeof(father)); 193 memset(sons,0,sizeof(sons)); 194 195 for (int i=1;i<=n;i++) data[i]=INT(); 196 197 for (int i=1;i<=m;i++) 198 { 199 int a,b; 200 a=INT(); 201 b=INT(); 202 edge[i*2].a=a; 203 edge[i*2].b=b; 204 edge[i*2-1].a=b; 205 edge[i*2-1].b=a; 206 } 207 m*=2; 208 sort(&edge[1],&edge[m+1],op); 209 memset(num,0,sizeof(num)); 210 int o=-1; 211 for (int i=1;i<=m;i++) 212 { 213 if (o!=edge[i].a) 214 { 215 o=edge[i].a; 216 start[o]=i; 217 } 218 num[o]++; 219 } 220 memset(root,0,sizeof(root)); 221 bfs(1); 222 223 for (int i=1;i<=p;i++) 224 { 225 char s; 226 s=CHAR(); 227 switch(s) 228 { 229 case 'I': 230 int c1,c2,k; 231 c1=INT();c2=INT();k=INT(); 232 update(c1,c2,k); 233 break; 234 case 'D': 235 c1=INT();c2=INT();k=INT(); 236 update(c1,c2,-k); 237 break; 238 case 'Q': 239 int c; 240 c=INT(); 241 splay(c); 242 printf("%d\n",data[c]); 243 } 244 } 245 } 246 247 return 0; 248 }
解2:
由于这里的树结构是固定不变的,因此也可以使用树链剖分来做。
【教训】
......DFS剖分爆栈的问题还是比较严重啊......T_T......也是第一次写,没经验,差错查了好久,用BFS代替之
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : HDU 3966_TreeCut 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 12 using namespace std; 13 14 #define MAXN (int)5E4+10 15 #define MAXM (int)1E5+10 16 17 int n; 18 19 int son[MAXN]; 20 int father[MAXN],size[MAXN],level[MAXN],data[MAXN],top[MAXN]; 21 int start[MAXN],num[MAXN]; 22 23 typedef struct nod 24 { 25 int a,b; 26 } node; 27 node edge[MAXM]; 28 29 bool op(node a,node b) 30 { 31 if (a.a==b.a) return a.b<b.b; 32 else return a.a<b.a; 33 } 34 35 int lowbit(int s) 36 { 37 return s&(-s); 38 } 39 int c[MAXN],pos[MAXN]; 40 int tot; 41 42 void update(int x,int s) 43 { 44 while (x<=n) 45 { 46 c[x]+=s; 47 x+=lowbit(x); 48 } 49 } 50 51 int sum(int x) 52 { 53 int t=0; 54 while (x>0) 55 { 56 t+=c[x]; 57 x-=lowbit(x); 58 } 59 return t; 60 } 61 62 void dfs(int now,int front,int d) 63 { 64 level[now]=d; 65 father[now]=front; 66 size[now]=1; 67 for (int i=0;i<num[now];i++) 68 { 69 int temp=edge[start[now]+i].b; 70 if (temp!=front) 71 { 72 dfs(temp,now,d+1); 73 size[now]+=size[temp]; 74 if (son[now]==0||size[temp]>size[son[now]]) son[now]=temp; 75 } 76 } 77 } 78 79 int q[MAXN]; 80 void bfs() 81 { 82 int head=1,tail=1; 83 q[1]=1; 84 level[1]=0; 85 father[1]=0; 86 while(head<=tail) 87 { 88 int now=q[head]; 89 size[now]=1; 90 for (int i=0;i<num[now];i++) 91 { 92 int temp=edge[start[now]+i].b; 93 if (temp!=father[now]) 94 { 95 father[temp]=now; 96 level[temp]=level[now]+1; 97 tail++; 98 q[tail]=temp; 99 } 100 } 101 head++; 102 } 103 for (int i=n;i>=1;i--) 104 { 105 int now=q[i]; 106 if (father[now]) 107 { 108 size[father[now]]+=size[now]; 109 if (son[father[now]]==0||size[now]>size[son[father[now]]]) 110 son[father[now]]=now; 111 } 112 } 113 114 for (int i=1;i<=n;i++) 115 { 116 int now=q[i]; 117 if (son[father[now]]==now) top[now]=top[father[now]]; 118 else 119 { 120 top[now]=now; 121 while(now) 122 { 123 tot++; 124 pos[now]=tot; 125 now=son[now]; 126 } 127 } 128 } 129 } 130 131 void treecut(int now,int root) 132 { 133 top[now]=root; 134 tot++; 135 pos[now]=tot; 136 137 if (!son[now]) return ; 138 treecut(son[now],root); 139 140 for (int i=0;i<num[now];i++) 141 { 142 int temp=edge[start[now]+i].b; 143 if (temp!=father[now]&&temp!=son[now]) treecut(temp,temp); 144 } 145 } 146 147 void change(int x,int y,int value) 148 { 149 while(top[x]!=top[y]) 150 { 151 if (level[top[x]]<level[top[y]]) swap(x,y); 152 update(pos[top[x]],value); 153 update(pos[x]+1,-value); 154 x=father[top[x]]; 155 } 156 if (level[x]>level[y]) swap(x,y); 157 158 update(pos[x],value); 159 update(pos[y]+1,-value); 160 } 161 162 int main() 163 { 164 freopen("3966.txt","r",stdin); 165 166 int m,p; 167 while(scanf("%d%d%d",&n,&m,&p)!=EOF) 168 { 169 for (int i=1;i<=n;i++) scanf("%d",&data[i]); 170 171 for (int i=1;i<=m;i++) 172 { 173 int a,b; 174 scanf("%d%d",&a,&b); 175 edge[i*2].a=a; 176 edge[i*2].b=b; 177 edge[i*2-1].a=b; 178 edge[i*2-1].b=a; 179 } 180 m*=2; 181 sort(&edge[1],&edge[m+1],op); 182 memset(num,0,sizeof(num)); 183 int o=-1; 184 for (int i=1;i<=m;i++) 185 { 186 if (o!=edge[i].a) 187 { 188 o=edge[i].a; 189 start[o]=i; 190 } 191 num[o]++; 192 } 193 194 memset(son,0,sizeof(son)); 195 tot=0; 196 //dfs(1,0,0); 197 //treecut(1,1); 198 bfs(); 199 200 memset(c,0,sizeof(c)); 201 for (int i=1;i<=n;i++) 202 { 203 update(pos[i],data[i]); 204 update(pos[i]+1,-data[i]); 205 } 206 207 for (int i=1;i<=p;i++) 208 { 209 char s; 210 s=getchar(); 211 while (s!='Q'&&s!='I'&&s!='D') s=getchar(); 212 if (s=='Q') 213 { 214 int cc; 215 scanf("%d",&cc); 216 printf("%d\n",sum(pos[cc])); 217 } else 218 { 219 int c1,c2,k; 220 scanf("%d%d%d",&c1,&c2,&k); 221 if (s=='D') k=-k; 222 change(c1,c2,k); 223 } 224 } 225 } 226 227 return 0; 228 }
Do Cool Things That Matter!