[SDOI2011]染色
考虑直接维护一个类。
写merge。
inline void merge(S &a,S b,S c){//b + c -> a
a.v = b.v + c.v;
if(b.li == 0){
a.li = c.li;
a.ri = c.ri;
}else{
if(c.li == 0){
a.li = b.li;
a.ri = b.ri;
}else{
a.li = b.li;
a.ri = c.ri;
a.v -= (b.ri == c.li);
}
}
}
随便上个树剖。
然后考虑怎么计算答案。
考虑把路径分成三部分\([u->lca)[lca,lca](lca,v]\)
考虑到我们在树剖时从下往上维护的一个类。
他的左端点是底部,右端点是顶部。所以要翻转一个类。
写了1h左右,不是很难写。
// Problem: P2486 [SDOI2011]染色
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2486
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<cstdio>
#define ll long long
#define N 100005
struct P{
int to,next;
}e[N << 1];
ll n,q;
ll head[N],cnt;
inline void add(int x,int y){
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
//tree
ll f[N],dep[N],top[N],dfncnt,dfn[N],inv[N],to[N],son[N],siz[N];
ll w[N];
inline void dfs(int u,int fa){
dep[u] = dep[fa] + 1;
f[u] = fa;
siz[u] = 1;
for(int i = head[u];i;i = e[i].next){
int v = e[i].to;
if(v == fa)
continue;
dfs(v,u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]])
son[u] = v;
}
}
inline void dfs2(int u,int t){
top[u] = t;
dfn[u] = ++dfncnt;
inv[dfncnt] = u;
if(son[u])dfs2(son[u],t);
for(int i = head[u];i;i = e[i].next){
int v = e[i].to;
if(v == f[u] || v == son[u])continue;
dfs2(v,v);
}
}
inline ll get(int x,int y){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) std::swap(x,y);
x= f[top[x]];
}
if(dep[x] > dep[y])std::swap(x,y);
return x;
}
//tree-cut
#define mid ((l + r) >> 1)
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
struct S{
int li,ri,v;
S(){li = ri = v = 0;}
}t[N << 2];
ll tag[N << 2];
inline void merge(S &a,S b,S c){//b + c -> a
a.v = b.v + c.v;
if(b.li == 0){
a.li = c.li;
a.ri = c.ri;
}else{
if(c.li == 0){
a.li = b.li;
a.ri = b.ri;
}else{
a.li = b.li;
a.ri = c.ri;
a.v -= (b.ri == c.li);
}
}
}
inline void build(int u,int l,int r){
if(l == r){
t[u].v = 1;
t[u].li = t[u].ri = w[inv[l]];
return ;
}
build(ls(u),l,mid);
build(rs(u),mid + 1,r);
merge(t[u],t[ls(u)],t[rs(u)]);
}
inline void del(int u){
if(tag[u]){
t[u].li = t[u].ri = tag[u];
t[u].v = 1;
return;
}
}
inline void down(int u){
if(tag[u]){
tag[ls(u)] = tag[u];
tag[rs(u)] = tag[u];
del(ls(u));
del(rs(u));
tag[u] = 0;
}
}
inline void change(int u,int l,int r,int tl,int tr,int to){
if(tl <= l && r <= tr){
tag[u] = to;
del(u);
return;
}
down(u);
if(tl <= mid)
change(ls(u),l,mid,tl,tr,to);
if(tr > mid)
change(rs(u),mid + 1,r,tl,tr,to);
merge(t[u],t[ls(u)],t[rs(u)]);
}
inline S que(int u,int l,int r,int tl,int tr){
S k1,k2;
if(tr < tl)
return k1;
if(tl <= l && r <= tr)
return t[u];
down(u);
if(tl <= mid)
k1 = que(ls(u),l,mid,tl,tr);
if(tr > mid)
k2 = que(rs(u),mid + 1,r,tl,tr);
S ans;
merge(ans,k1,k2);
return ans;
}
//seg
inline void dfs3(int u,int l,int r){
if(l == r){
std::cout<<t[u].li<<" "<<t[u].ri<<" "<<t[u].v<<" "<<l<<" "<<r<<std::endl;
return ;
}
dfs3(ls(u),l,mid);
dfs3(rs(u),mid + 1,r);
std::cout<<t[u].li<<" "<<t[u].ri<<" "<<t[u].v<<" "<<l<<" "<<r<<std::endl;
return ;
}
int main(){
scanf("%lld%lld",&n,&q);
for(int i = 1;i <= n;++i){
scanf("%lld",&w[i]);
}
for(int i = 1;i < n;++i){
ll x,y;
scanf("%lld%lld",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
dfs2(1,0);
build(1,1,n);
// for(int i = 1;i <= n;++i)
// std::cout<<son[i]<<" "<<dfn[i]<<std::endl;
// dfs3(1,1,n);
while(q -- ){
char a;
while(a != 'Q' && a != 'C')
a = getchar();
if(a == 'Q'){
ll x,y;
scanf("%lld%lld",&x,&y);
ll lca = get(x,y);
// std::cout<<lca<<std::endl;
S ans;
S z;
while(top[x] != top[lca]){
merge(ans,z = que(1,1,n,dfn[top[x]],dfn[x]),ans);
// std::cout<<dfn[top[x]]<<" "<<dfn[x]<<std::endl;x = f[top[x]];
// std::cout<<z.li<<" "<<z.ri<<" "<<z.v<<"QWQ"<<std::endl;
// std::cout<<ans.li<<" "<<ans.ri<<" "<<ans.v<<std::endl;
x = f[top[x]];
}
merge(ans,que(1,1,n,dfn[lca] + 1,dfn[x]),ans);
// std::cout<<dfn[lca] + 1<<" "<<dfn[x]<<std::endl;
S ans2;
while(top[y] != top[lca]){
merge(ans2,que(1,1,n,dfn[top[y]],dfn[y]),ans2);
// std::cout<<dfn[top[y]]<<" "<<dfn[y]<<std::endl;
// std::cout<<ans2.li<<" "<<ans2.ri<<" "<<ans2.v<<std::endl;
y = f[top[y]];
}
merge(ans2,que(1,1,n,dfn[lca] + 1,dfn[y]),ans2);
// std::cout<<dfn[lca] + 1<<" "<<dfn[y]<<std::endl;
// std::cout<<ans2.li<<" "<<ans2.ri<<" "<<ans2.v<<std::endl;
std::swap(ans.li,ans.ri);
merge(ans,ans,que(1,1,n,dfn[lca],dfn[lca]));
//std::cout<<ans.li<<" "<<ans.ri<<" "<<ans.v<<std::endl;
merge(ans,ans,ans2);
std::cout<<ans.v<<std::endl;
}else{
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]])std::swap(x,y);
change(1,1,n,dfn[top[x]],dfn[x],z);
x = f[top[x]];
}
if(dep[x] > dep[y]) std::swap(x,y);
change(1,1,n,dfn[x],dfn[y],z);
}
a = '.';
}
}