0%

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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : HDU 3966
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

#define MAXN (int)5E4+10
#define MAXM (int)1E5+10

typedef struct nod
{
int a,b;
} node;
node edge[MAXM];

bool op(node a,node b)
{
if (a.a==b.a) return a.b<b.b;
else return a.a<b.a;
}

int sons[MAXN][2];
int father[MAXN],size[MAXN],data[MAXN],change[MAXN];
int start[MAXN],num[MAXN];
bool root[MAXN];

void bfs(int s)
{
queue<int>q;
q.push(s);
root[s]=true;
change[s]=0;
while(!q.empty())
{
int now=q.front();
for (int i=0;i<num[now];i++)
if (!root[edge[start[now]+i].b])
{
father[edge[start[now]+i].b]=now;
root[edge[start[now]+i].b]=true;
change[edge[start[now]+i].b]=0;
q.push(edge[start[now]+i].b);
}
q.pop();
}
}

void down(int x)
{
if (change[x])
{
data[x]+=change[x];
change[sons[x][0]]+=change[x];
change[sons[x][1]]+=change[x];
change[x]=0;
}
}

void rotate(int x,int w) //rotate(node,0/1)
{
int y=father[x];

down(y);
down(x);

sons[y][!w]=sons[x][w];
if (sons[x][w]) father[sons[x][w]]=y;
father[x]=father[y];
if (father[y]&&(!root[y])) sons[father[y]][y==sons[father[y]][1]]=x;
sons[x][w]=y;
father[y]=x;

if (root[y])
{
root[x]=true;
root[y]=false;
}
}

void splay(int x) //splay(node)
{
down(x);
while(!root[x])
{
if (root[father[x]]) rotate(x,x==sons[father[x]][0]);
else
{
int t=father[x];
int w=(sons[father[t]][0]==t);
if (sons[t][w]==x)
{
rotate(x,!w);
rotate(x,w);
} else
{
rotate(t,w);
rotate(x,w);
}
}
}
}

void splay____(int x) //splay(node)
{
down(x);
while(!root[x])
{
if (sons[father[x]][0]==x) rotate(x,1);
else rotate(x,0);
}
}

void access(int v)
{
int u=v;
v=0;
while(u)
{
splay(u);
down(u);
root[sons[u][1]]=true;
sons[u][1]=v;
root[v]=false;
v=u;
u=father[u];
}
}

void update(int v,int u,int k)
{
access(v);
v=0;
while(u)
{
splay(u);
if (!father[u])
{
data[u]+=k;
change[v]+=k;
change[sons[u][1]]+=k;
return;
}
down(u);
root[sons[u][1]]=true;
sons[u][1]=v;
root[v]=false;
v=u;
u=father[u];
}
}

int INT() {
char ch;
int res;
bool neg;
while (ch = getchar(), !isdigit(ch) && ch != '-')
;
if (ch == '-') {
neg = true;
res = 0;
} else {
neg = false;
res = ch - '0';
}
while (ch = getchar(), isdigit(ch))
res = res * 10 + ch - '0';
return neg ? -res : res;
}

char CHAR() {
char res;
while (res = getchar(), !isalpha(res))
;
return res;
}

int main()
{
// freopen("3966.txt","r",stdin);

int n,m,p;
while(scanf("%d%d%d",&n,&m,&p)!=EOF)
{
memset(father,0,sizeof(father));
memset(sons,0,sizeof(sons));

for (int i=1;i<=n;i++) data[i]=INT();

for (int i=1;i<=m;i++)
{
int a,b;
a=INT();
b=INT();
edge[i*2].a=a;
edge[i*2].b=b;
edge[i*2-1].a=b;
edge[i*2-1].b=a;
}
m*=2;
sort(&edge[1],&edge[m+1],op);
memset(num,0,sizeof(num));
int o=-1;
for (int i=1;i<=m;i++)
{
if (o!=edge[i].a)
{
o=edge[i].a;
start[o]=i;
}
num[o]++;
}
memset(root,0,sizeof(root));
bfs(1);

for (int i=1;i<=p;i++)
{
char s;
s=CHAR();
switch(s)
{
case 'I':
int c1,c2,k;
c1=INT();c2=INT();k=INT();
update(c1,c2,k);
break;
case 'D':
c1=INT();c2=INT();k=INT();
update(c1,c2,-k);
break;
case 'Q':
int c;
c=INT();
splay(c);
printf("%d\n",data[c]);
}
}
}

return 0;
}

解2:树链剖分

由于这里的树结构是固定不变的,因此也可以使用树链剖分来做。

教训

……DFS剖分爆栈的问题还是比较严重啊……T_T……也是第一次写,没经验,差错查了好久,用BFS代替之

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : HDU 3966_TreeCut
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define MAXN (int)5E4+10
#define MAXM (int)1E5+10

int n;

int son[MAXN];
int father[MAXN],size[MAXN],level[MAXN],data[MAXN],top[MAXN];
int start[MAXN],num[MAXN];

typedef struct nod
{
int a,b;
} node;
node edge[MAXM];

bool op(node a,node b)
{
if (a.a==b.a) return a.b<b.b;
else return a.a<b.a;
}

int lowbit(int s)
{
return s&(-s);
}
int c[MAXN],pos[MAXN];
int tot;

void update(int x,int s)
{
while (x<=n)
{
c[x]+=s;
x+=lowbit(x);
}
}

int sum(int x)
{
int t=0;
while (x>0)
{
t+=c[x];
x-=lowbit(x);
}
return t;
}

void dfs(int now,int front,int d)
{
level[now]=d;
father[now]=front;
size[now]=1;
for (int i=0;i<num[now];i++)
{
int temp=edge[start[now]+i].b;
if (temp!=front)
{
dfs(temp,now,d+1);
size[now]+=size[temp];
if (son[now]==0||size[temp]>size[son[now]]) son[now]=temp;
}
}
}

int q[MAXN];
void bfs()
{
int head=1,tail=1;
q[1]=1;
level[1]=0;
father[1]=0;
while(head<=tail)
{
int now=q[head];
size[now]=1;
for (int i=0;i<num[now];i++)
{
int temp=edge[start[now]+i].b;
if (temp!=father[now])
{
father[temp]=now;
level[temp]=level[now]+1;
tail++;
q[tail]=temp;
}
}
head++;
}
for (int i=n;i>=1;i--)
{
int now=q[i];
if (father[now])
{
size[father[now]]+=size[now];
if (son[father[now]]==0||size[now]>size[son[father[now]]])
son[father[now]]=now;
}
}

for (int i=1;i<=n;i++)
{
int now=q[i];
if (son[father[now]]==now) top[now]=top[father[now]];
else
{
top[now]=now;
while(now)
{
tot++;
pos[now]=tot;
now=son[now];
}
}
}
}

void treecut(int now,int root)
{
top[now]=root;
tot++;
pos[now]=tot;

if (!son[now]) return ;
treecut(son[now],root);

for (int i=0;i<num[now];i++)
{
int temp=edge[start[now]+i].b;
if (temp!=father[now]&&temp!=son[now]) treecut(temp,temp);
}
}

void change(int x,int y,int value)
{
while(top[x]!=top[y])
{
if (level[top[x]]<level[top[y]]) swap(x,y);
update(pos[top[x]],value);
update(pos[x]+1,-value);
x=father[top[x]];
}
if (level[x]>level[y]) swap(x,y);

update(pos[x],value);
update(pos[y]+1,-value);
}

int main()
{
freopen("3966.txt","r",stdin);

int m,p;
while(scanf("%d%d%d",&n,&m,&p)!=EOF)
{
for (int i=1;i<=n;i++) scanf("%d",&data[i]);

for (int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
edge[i*2].a=a;
edge[i*2].b=b;
edge[i*2-1].a=b;
edge[i*2-1].b=a;
}
m*=2;
sort(&edge[1],&edge[m+1],op);
memset(num,0,sizeof(num));
int o=-1;
for (int i=1;i<=m;i++)
{
if (o!=edge[i].a)
{
o=edge[i].a;
start[o]=i;
}
num[o]++;
}

memset(son,0,sizeof(son));
tot=0;
//dfs(1,0,0);
//treecut(1,1);
bfs();

memset(c,0,sizeof(c));
for (int i=1;i<=n;i++)
{
update(pos[i],data[i]);
update(pos[i]+1,-data[i]);
}

for (int i=1;i<=p;i++)
{
char s;
s=getchar();
while (s!='Q'&&s!='I'&&s!='D') s=getchar();
if (s=='Q')
{
int cc;
scanf("%d",&cc);
printf("%d\n",sum(pos[cc]));
} else
{
int c1,c2,k;
scanf("%d%d%d",&c1,&c2,&k);
if (s=='D') k=-k;
change(c1,c2,k);
}
}
}

return 0;
}