luogu题解P3950部落冲突--树链剖分

题目链接

https://www.luogu.org/problemnew/show/P3950

分析

大佬都用LCT,我太弱只会树链剖分

一个很裸的维护边权树链剖分题.按照套路,对于一条边$(dep(u)<dep(v))$,让它边权加1就在$v$点处+1,将边的问题转化为点的问题

然后对于C,U操作,线段树单点修改,Q操作区间查询

注意

  • 询问$u,v(dep(u)>dep(v))$点之间是否联通区间查询时注意是查询$[u,son[v]]$的和,忽然发现NOI赛场上Day2用树链剖分写得暴力为什么错了。。。

  • 单点修改注意是修改$dfn[x]$那个点,查了好久的错

代码

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
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
#include <cmath>
#define ll long long
#define ri register int
using namespace std;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return;
}
const int maxn=300005;
const int inf=0x7fffffff;
struct Edge{
int ne,to;
}edge[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
h[f]=num_edge;
}
int dfn[maxn],tot=0,top[maxn],dep[maxn],fa[maxn],son[maxn],size[maxn];
void dfs_1(int now){
int v;size[now]=1;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa[now])continue;
fa[v]=now,dep[v]=dep[now]+1;
dfs_1(v);
size[now]+=size[v];
if(!son[now]||size[son[now]]<size[v])son[now]=v;
}
return ;
}
void dfs_2(int now,int t){
int v;dfn[now]=++tot,top[now]=t;
if(!son[now])return ;
dfs_2(son[now],t);
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa[now]||v==son[now])continue;
dfs_2(v,v);
}
return ;
}
int sum[maxn<<2],L,R,dta,t;
void update(int now,int l,int r){
if(l==r){
sum[now]+=dta;
return ;
}
int mid=(l+r)>>1;
if(t<=mid)update(now<<1,l,mid);
else update(now<<1|1,mid+1,r);
sum[now]=sum[now<<1]+sum[now<<1|1];
return ;
}
int query(int now,int l,int r){
if(L<=l&&r<=R){
return sum[now];
}
int mid=(l+r)>>1,ans=0;
if(L<=mid)ans+=query(now<<1,l,mid);
if(mid<R)ans+=query(now<<1|1,mid+1,r);
//cout<<l<<' '<<r<<' '<<ans<<endl;
return ans;
}
int n,m;
struct War{
int x,y;
}war[maxn];
int query_path(int x,int y){
int tmp=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
L=dfn[top[x]],R=dfn[x];
tmp=query(1,1,n);
//cout<<tmp<<endl;
if(tmp!=0)return 0;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
L=dfn[x]+1,R=dfn[y];
if(L>R)return 1;
tmp=query(1,1,n);//puts("f***");
//cout<<tmp<<endl;
if(tmp!=0)return 0;
return 1;
}
inline void update_path(int x,int y,int z){
dta=z;
if(dep[x]<dep[y])swap(x,y);
t=dfn[x];
update(1,1,n);
//L=1,R=n;
//printf("%d\n",query(1,1,n));
return ;
}
int main(){
char opt[5];
int x,y,z,cnt=0;
read(n),read(m);
for(ri i=1;i<n;i++){
read(x),read(y);
add_edge(x,y);
add_edge(y,x);
}
dep[1]=1,fa[1]=0;
dfs_1(1);
dfs_2(1,1);
memset(sum,0,sizeof(sum));
for(ri i=1;i<=m;i++){
scanf("%s",opt);
if(opt[0]=='Q'){
read(x),read(y);
if(query_path(x,y))puts("Yes");
else puts("No");
}
else if(opt[0]=='C'){
read(x),read(y);
war[++cnt].x=x;
war[cnt].y=y;
update_path(x,y,1);
}
else{
read(z);
x=war[z].x,y=war[z].y;
update_path(x,y,-1);
}
}
return 0;
}