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.
 
【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.
 
 
【分析】
解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 }
View Code

 

 
解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 }
View Code

 

 
posted @ 2015-04-27 20:13  辰帆  阅读(227)  评论(0编辑  收藏  举报