P2486 [SDOI2011]染色

被吊打捏。

本来想到了一种强制边权挂点的做法,然后被自己想的菊花图给 $\text{hack}$ 了。复杂度是假的,大概 $\mathcal O(nq)$ 的。所以这里讲一下 $\text{Rusun}$ 巨佬的思路。

首先肯定是考虑树剖(似乎这道题还可以用 $\text{Link/Cut Tree}$ 做,不过我想不到)。

对于答案的贡献,肯定在于两端颜色的交界,所以就是我们需要考虑的。

在线段树合并时,两个区间交界的地方如果颜色相同,那明显答案不能够再次统计,则需要 --Tree[p].val

维护一个 $Tree[p].lc,Tree[p].rc$ 分别表示左端点颜色和右端点颜色即可。

对于查询,我们将路径拆分成两段 $(x,lca_{x,y}),(lca_{x,y},y)$ ,此时的 $lca_{x,y}$ 并不一定指真正的 $lca$ ,而是宏定义 $lca_{x,y}$ 所在的链上。然后根据上述的方法跳区间即可。

AC Code
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
#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=1e5+10;
int N,M,Col[MAXN],Val[MAXN];
struct G
{
int next,to;
}Edge[MAXN<<1];
int Head[MAXN],Total;
inline void addEdge(int u,int v)
{
Edge[++Total]=(G){Head[u],v};Head[u]=Total;
Edge[++Total]=(G){Head[v],u};Head[v]=Total;
}
int Son[MAXN],Siz[MAXN],Fa[MAXN],Dep[MAXN];
void dfsTree(int x,int last)
{
Dep[x]=Dep[last]+1,Fa[x]=last,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)
{
Top[x]=topf,Dfn[x]=++Cnt;
Val[Cnt]=Col[x];
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);
}
}
const int INF=0x3f3f3f3f;
struct Segment
{
int l,r,val,tag,lc,rc;
}Tree[MAXN<<2];
#define ls p<<1
#define rs p<<1|1
inline void pushUp(int p)
{
Tree[p].val=Tree[ls].val+Tree[rs].val;
if(Tree[ls].rc==Tree[rs].lc) --Tree[p].val;
Tree[p].lc=Tree[ls].lc;
Tree[p].rc=Tree[rs].rc;
}
inline void pushDown(int p)
{
if(Tree[p].tag)
{
Tree[ls].val=Tree[rs].val=1;
Tree[ls].lc=Tree[ls].rc=Tree[p].tag,
Tree[rs].lc=Tree[rs].rc=Tree[p].tag;
Tree[ls].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;
if(l==r)
{
Tree[p].val=1;
Tree[p].lc=Tree[p].rc=Val[l];
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushUp(p);
}
void modify(int p,int l,int r,int c)
{
if(l<=Tree[p].l&&Tree[p].r<=r)
{
Tree[p].val=1;
Tree[p].lc=Tree[p].rc=c;
Tree[p].tag=c;
return ;
}
pushDown(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid) modify(ls,l,r,c);
if(mid<r) modify(rs,l,r,c);
pushUp(p);
}
Segment query(int p,int l,int r)
{
if(l<=Tree[p].l&&Tree[p].r<=r) return Tree[p];
pushDown(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(r<=mid) return query(ls,l,r);
else if(mid<l) return query(rs,l,r);
Segment res,lres=query(ls,l,r),rres=query(rs,l,r);
res.lc=lres.lc,res.rc=rres.rc,res.val=lres.val+rres.val;
if(lres.rc==rres.lc) --res.val;
return res;
}
inline void modifyPath(int x,int y,int c)
{
while(Top[x]!=Top[y])
{
if(Dep[Top[x]]<Dep[Top[y]]) std::swap(x,y);
modify(1,Dfn[Top[x]],Dfn[x],c);
x=Fa[Top[x]];
}
if(Dep[x]>Dep[y]) std::swap(x,y);
modify(1,Dfn[x],Dfn[y],c);
}
inline int queryPath(int x,int y)
{
int res=0,xlc=-1,ylc=-1;
while(Top[x]!=Top[y])
{
if(Dep[Top[x]]>Dep[Top[y]])
{
Segment q=query(1,Dfn[Top[x]],Dfn[x]);
res+=q.val;
if(xlc==q.rc) --res;
xlc=q.lc,x=Fa[Top[x]];
}
else
{
Segment q=query(1,Dfn[Top[y]],Dfn[y]);
res+=q.val;
if(ylc==q.rc) --res;
ylc=q.lc,y=Fa[Top[y]];
}
}
if(Dep[x]>Dep[y]) std::swap(x,y),std::swap(xlc,ylc);
Segment q=query(1,Dfn[x],Dfn[y]);
res+=q.val;
if(xlc==q.lc) --res;
if(ylc==q.rc) --res;
return res;
}
char opt[3];
int main()
{
// freopen("tree-chain.in","r",stdin);
// freopen("tree-chain.out","w",stdout);
read(N,M);
for(int i=1;i<=N;++i) read(Col[i]);
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);
for(int u,v,c;M--;)
{
scanf("%s",opt+1);
if(opt[1]=='C')
{
read(u,v,c);
modifyPath(u,v,c);
}
else
{
read(u,v);
write(queryPath(u,v)),puts("");
}
}
return 0;
}
/*
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
*/