[SDOI2011]染色 树链剖分
LG传送门
我写这道题的题解主要是因为洛谷上的题解要么讲的不清要么代码丑滑稽,导致初学时的我调了很久,所以想发个题解方便后来人。
由于要维护的信息还是具有区间可加性,只需要记录一下每个区间的左右端点颜色,就可以用树剖+线段树维护。
还不会的同学可以看我的树链剖分总结和线段树总结。
废话不多说直接上代码:看的时候注意一下upd(update)、psu(pushup)、qry(query)、qry0四个函数就好了。
#include<cstdio>
#define R register
#define I inline
using namespace std;
const int S=100003,N=200003,M=400003;
int h[S],s[N],g[N],d[S],t[S],p[S],q[S],r[S],f[S],w[S],u[S],o[M],v[M],a[M],b[M],c,e,n;
I void swp(int &x,int &y){x^=y,y^=x,x^=y;}
I void add(int x,int y){s[++c]=h[x],h[x]=c,g[c]=y;}
I void upd(int k,int z){o[k]=1,v[k]=a[k]=b[k]=z;}
I void psu(int k,int p,int q){
o[k]=o[p]+o[q],a[k]=a[p],b[k]=b[q];
if(b[p]==a[q]) --o[k];
}
I void psd(int k){if(v[k]){R int p=k<<1,q=p|1,z=v[k]; upd(p,z),upd(q,z),v[k]=0;}}
void bld(int k,int l,int r){
if(l==r){o[k]=1,a[k]=b[k]=u[l]; return ;}
R int p=k<<1,q=p|1,m=l+r>>1;
bld(p,l,m),bld(q,m+1,r),psu(k,p,q);
}
void mdf(int k,int l,int r,int x,int y,int z){
if(x<=l&&r<=y){upd(k,z); return ;}
R int p=k<<1,q=p|1,m=l+r>>1; psd(k);
if(x<=m) mdf(p,l,m,x,y,z);
if(y>m) mdf(q,m+1,r,x,y,z);
psu(k,p,q);
}
int qry(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return o[k];
R int p=k<<1,q=p|1,m=l+r>>1,o=0; psd(k);
if(x<=m) o+=qry(p,l,m,x,y);
if(y>m) o+=qry(q,m+1,r,x,y);
if(x<=m&&y>m) o-=b[p]==a[q];
return o;
}
int col(int k,int l,int r,int x){
if(l==r) return a[k];
R int p=k<<1,q=p|1,m=l+r>>1; psd(k);
if(x<=m) return col(p,l,m,x);
return col(q,m+1,r,x);
}
void dfs1(int x,int f){d[x]=d[f]+1,p[x]=f,t[x]=1;
for(R int i=h[x],y,m=0;i;i=s[i])
if((y=g[i])^f){dfs1(y,x),t[x]+=t[y];
if(t[y]>m) m=t[y],q[x]=y;
}
}
void dfs2(int x,int t){f[x]=++e,u[e]=w[x],r[x]=t;
if(!q[x]) return ; dfs2(q[x],t);
for(R int i=h[x],y;i;i=s[i])
if((y=g[i])^p[x]&&y^q[x]) dfs2(y,y);
}
I void mdf0(int x,int y,int z){
while(r[x]^r[y]){
if(d[r[x]]<d[r[y]]) swp(x,y);
mdf(1,1,n,f[r[x]],f[x],z),x=p[r[x]];
}
if(d[x]>d[y]) swp(x,y);
mdf(1,1,n,f[x],f[y],z);
}
I int qry0(int x,int y){
R int o=0,a=0,b=0;
while(r[x]^r[y]){
if(d[r[x]]<d[r[y]]) swp(x,y),swp(a,b); if(col(1,1,n,f[x])==a) --o;
o+=qry(1,1,n,f[r[x]],f[x]),a=col(1,1,n,f[r[x]]),x=p[r[x]];
}
if(d[x]>d[y]) swp(x,y),swp(a,b);
if(col(1,1,n,f[x])==a) --o; if(col(1,1,n,f[y])==b) --o;
return o+qry(1,1,n,f[x],f[y]);
}
int main(){
freopen("in","r",stdin);
freopen("a.out","w",stdout);
R int m,i,x,y,z; R char o[2];
for(scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%d",&w[i]);
for(i=1;i<n;++i) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs1(1,0),dfs2(1,1),bld(1,1,n);
for(i=1;i<=m;++i){scanf("%s%d%d",o,&x,&y);
if(o[0]=='C') scanf("%d",&z),mdf0(x,y,z);
else printf("%d\n",qry0(x,y));
}
return 0;
}