P3950 部落冲突

多种解法的树上带修连通块查询。

很久一道用很暴力的树剖写过一遍,每发生一次战争,就将其简单路径的权值加一;反之,路径权值减一,然后查询区间和是否为零即可。

然后学了 $\text{Link/Cut Tree}$ ,这道题就更暴力了,直接暴力删边,暴力连边即可。

没开 $\text{O}_2$ 的话,树剖稍快;开了 $\text{O}_2$ 的话,差距不大。

AC Code TreeChain ver.
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
#include<bits/stdc++.h>
const int MAXN=3e5+10;
template<class T>
inline void read(T &x)
{
x=0;
char ch=getchar(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1)
{
read(x),read(x1...);
}
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int N,Q;
struct TC
{
int next,to;
}Edge[MAXN<<1];
int Head[MAXN],Total;
inline void addEdge(int u,int v)
{
Edge[++Total]=(TC){Head[u],v};Head[u]=Total;
Edge[++Total]=(TC){Head[v],u};Head[v]=Total;
}
int Fa[MAXN],Son[MAXN],Dep[MAXN],Siz[MAXN];
void dfsTree(int x,int last)
{
Fa[x]=last,Dep[x]=Dep[last]+1,Siz[x]=1;
for(int e=Head[x],v;e;e=Edge[e].next)
{
if((v=Edge[e].to)==last) continue;
dfsTree(v,x);
Siz[x]+=Siz[v];
if(!Son[x]||Siz[v]>Siz[Son[x]]) Son[x]=v;
}
}
int Top[MAXN],Dfn[MAXN],Cnt;
void dfsChain(int x,int topf)
{
Dfn[x]=++Cnt,Top[x]=topf;
if(!Son[x]) return ;
dfsChain(Son[x],topf);
for(int e=Head[x],v;e;e=Edge[e].next)
{
if((v=Edge[e].to)==Fa[x]||v==Son[x]) continue;
dfsChain(v,v);
}
}
#define ls p<<1
#define rs p<<1|1
struct ST
{
int l,r,val,tag,siz;
}Tree[MAXN<<2];
inline void pushUp(int p)
{
Tree[p].val=Tree[ls].val+Tree[rs].val;
}
inline void pushDown(int p)
{
if(Tree[p].tag)
{
Tree[ls].val+=Tree[ls].siz*Tree[p].tag;
Tree[rs].val+=Tree[rs].siz*Tree[p].tag;
Tree[ls].tag+=Tree[p].tag,Tree[rs].tag+=Tree[p].tag;
Tree[p].tag=0;
}
}
void build(int p,int l,int r)
{
Tree[p].l=l,Tree[p].r=r,Tree[p].siz=r-l+1;
if(l==r) return ;
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
void modifyAdd(int p,int l,int r,int k)
{
if(l<=Tree[p].l&&Tree[p].r<=r)
{
Tree[p].val+=Tree[p].siz*k;
Tree[p].tag+=k;
return ;
}
pushDown(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid) modifyAdd(ls,l,r,k);
if(mid<r) modifyAdd(rs,l,r,k);
pushUp(p);
}
int querySum(int p,int l,int r)
{
if(l<=Tree[p].l&&Tree[p].r<=r) return Tree[p].val;
pushDown(p);
int mid=(Tree[p].l+Tree[p].r)>>1,res=0;
if(l<=mid) res+=querySum(ls,l,r);
if(mid<r) res+=querySum(rs,l,r);
return res;
}
inline void modifyAddPath(int x,int y,int k)
{
while(Top[x]!=Top[y])
{
if(Dep[Top[x]]<Dep[Top[y]]) std::swap(x,y);
modifyAdd(1,Dfn[Top[x]],Dfn[x],k);
x=Fa[Top[x]];
}
if(Dep[x]>Dep[y]) std::swap(x,y);
modifyAdd(1,Dfn[x]+1,Dfn[y],k);
}
inline bool querySumPath(int x,int y)
{
int res=0;
while(Top[x]!=Top[y])
{
if(Dep[Top[x]]<Dep[Top[y]]) std::swap(x,y);
res=querySum(1,Dfn[Top[x]],Dfn[x]);
if(res) return 1;
x=Fa[Top[x]];
}
if(Dep[x]>Dep[y]) std::swap(x,y);
res=querySum(1,Dfn[x]+1,Dfn[y]);
return res;
}
char opt[10];
struct War
{
int u,v;
}Wr[MAXN];
int Idx;
int main()
{
read(N,Q);
for(int i=2,u,v;i<=N;++i)
{
read(u,v);addEdge(u,v);
}
dfsTree(1,0);dfsChain(1,1);
build(1,1,N);
while(Q--)
{
scanf("%s",opt+1);
if(opt[1]=='U')
{
int Qx;read(Qx);
modifyAddPath(Wr[Qx].u,Wr[Qx].v,-1);
}
else
{
int Qx,Qy;
read(Qx,Qy);
if(opt[1]=='C')
{
Wr[++Idx]=(War){Qx,Qy};
modifyAddPath(Qx,Qy,1);
}
else puts(querySumPath(Qx,Qy)?"No":"Yes");
}
}
return 0;
}
/*
5 9
1 2
2 3
3 4
4 5
Q 1 4
C 2 1
C 4 3
Q 3 1
Q 1 5
U 1
U 2
C 4 3
Q 3 4
*/

AC Code LCT ver.
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
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<iomanip>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define gh() getchar()
#define re register
typedef long long ll;
template<class T>
inline void read(T &x)
{
x=0;
char ch=gh(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=gh();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=gh();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1)
{
read(x),read(x1...);
}
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<class T>
inline bool checkMax(T &x,T &y)
{
return x<y?x=y,1:0;
}
template<class T>
inline bool checkMin(T &x,T &y)
{
return x>y?x=y,1:0;
}
const int MAXN=3e5+10;
int N,M;
struct LCT
{
int chi[2],fa,rev;
}Tr[MAXN];
#define ls(p) Tr[p].chi[0]
#define rs(p) Tr[p].chi[1]
inline void pushRev(int p)
{
std::swap(ls(p),rs(p));
Tr[p].rev^=1;
}
inline void pushDown(int p)
{
if(Tr[p].rev)
{
pushRev(ls(p)),pushRev(rs(p));
Tr[p].rev=0;
}
}
inline bool isRoot(int x)
{
return (ls(Tr[x].fa)!=x&&rs(Tr[x].fa)!=x);
}
inline void rotate(int x)
{
int y=Tr[x].fa,z=Tr[y].fa;
int k=rs(y)==x;
if(!isRoot(y)) Tr[z].chi[rs(z)==y]=x;
Tr[x].fa=z;
Tr[y].chi[k]=Tr[x].chi[k^1],Tr[Tr[x].chi[k^1]].fa=y;
Tr[x].chi[k^1]=y,Tr[y].fa=x;
}
inline void Splay(int x)
{
int r=x,Top=0;
static int Stk[MAXN];
Stk[++Top]=r;
while(!isRoot(r)) Stk[++Top]=r=Tr[r].fa;
while(Top) pushDown(Stk[Top--]);
while(!isRoot(x))
{
int y=Tr[x].fa,z=Tr[y].fa;
if(!isRoot(y))
{
if((rs(z)==y)^(rs(y)==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
inline void access(int x)
{
int z=x;
for(int y=0;x;y=x,x=Tr[x].fa)
{
Splay(x);
rs(x)=y;
}
Splay(z);
}
inline void makeRoot(int x)
{
access(x);
pushRev(x);
}
inline int findRoot(int x)
{
access(x);
while(ls(x)) pushDown(x),x=ls(x);
return Splay(x),x;
}
inline void split(int x,int y)
{
makeRoot(x);
access(y);
}
inline void link(int x,int y)
{
makeRoot(x);
if(findRoot(y)!=x) Tr[x].fa=y;
}
inline void cut(int x,int y)
{
makeRoot(x);
if(findRoot(y)==x&&Tr[y].fa==x&&!ls(y)) rs(x)=Tr[y].fa=0;
}
inline bool edge(int x,int y)
{
return (findRoot(x)==findRoot(y));
}
char opt[3];
struct War
{
int u,v;
}W[MAXN];
int Cnt;
int main()
{
// freopen("LCT.in","r",stdin);
// freopen("LCT.out","w",stdout);
read(N,M);
for(int i=2,u,v;i<=N;++i)
{
read(u,v);link(u,v);
}
for(int u,v;M--;)
{
scanf("%s",opt+1);
if(opt[1]=='Q')
{
read(u,v);
puts(edge(u,v)?"Yes":"No");
}
else if(opt[1]=='C')
{
read(u,v);
cut(u,v);
W[++Cnt]=(War){u,v};
}
else
{
read(u);
link(W[u].u,W[u].v);
}
}
return 0;
}
/*
5 9
1 2
2 3
3 4
4 5
Q 1 4
C 2 1
C 4 3
Q 3 1
Q 1 5
U 1
U 2
C 4 3
Q 3 4
*/