P2486 [SDOI2011]染色

链接

调了好久。。。

我平常写平衡树时 \(push\) \(tag\) 的操作都习惯把 \(rev\) 数组清零,但在 \(LCT\) 中不行,因为 \(rev\) 储存了节点间的父子关系,直接清零会改变树的结构。

\(\frak{code}\)

#include<bits/stdc++.h>
#define IL inline
#define LL long long
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
using namespace std;
const int N=1e5+3;
int n,m;
IL int in(){
	char c;int f=1;
	while((c=getchar())<'0'||c>'9')
		if(c=='-') f=-1;
	int x=c-'0';
	while((c=getchar())>='0'&&c<='9')
		x=x*10+c-'0';
	return x*f;
}
struct LCT{
	int fa[N],ch[N][2],rev[N],tag[N],col[N],lc[N],rc[N],sum[N];
	IL int chk(int x){return rs(fa[x])==x;}
	IL int noroot(int x){return ls(fa[x])==x||rs(fa[x])==x;}
	IL void pushup(int x){
		if(ls(x)) lc[x]=lc[ls(x)];else lc[x]=col[x];
		if(rs(x)) rc[x]=rc[rs(x)];else rc[x]=col[x];
		sum[x]=sum[ls(x)]+sum[rs(x)]+1;
		if(ls(x)) sum[x]-=(col[x]==rc[ls(x)]);
		if(rs(x)) sum[x]-=(col[x]==lc[rs(x)]);
	}
	IL void Rev(int x){rev[x]^=1,swap(ls(x),rs(x)),swap(lc[x],rc[x]);}
	IL void Tag(int x,int v){tag[x]=col[x]=lc[x]=rc[x]=v,sum[x]=1;}
	IL void pushdown(int x){
		if(tag[x]){
			if(ls(x)) Tag(ls(x),tag[x]);
			if(rs(x)) Tag(rs(x),tag[x]);
			tag[x]=0;
		}
		if(rev[x]){
			if(ls(x)) Rev(ls(x));
			if(rs(x)) Rev(rs(x));
			rev[x]=0;
		}
	}
	IL void rotate(int x){
		int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
		if(noroot(y)) ch[z][chk(y)]=x;
		if(w) fa[w]=y;
		fa[y]=x,fa[x]=z,ch[x][k^1]=y,ch[y][k]=w;
		pushup(y),pushup(x);
	}
	void pushall(int x){
		if(noroot(x)) pushall(fa[x]);
		pushdown(x);
	}
	IL void splay(int x){
		pushall(x);
		while(noroot(x)){
			int y=fa[x];
			if(noroot(y))
				rotate(chk(x)^chk(y)?x:y);
			rotate(x);
		}
	}
	IL void access(int x){for(int y=0;x;x=fa[y=x]) splay(x),rs(x)=y,pushup(x);}
	IL void makeroot(int x){access(x),splay(x),Rev(x);}
	IL void split(int x,int y){makeroot(x),access(y),splay(y);}
	IL void link(int x,int y){makeroot(x),fa[x]=y;}
}T;
int main()
{
	char op[5];int x,y,z;
	n=in(),m=in();
	for(int i=1;i<=n;++i) T.col[i]=T.lc[i]=T.rc[i]=in(),T.sum[i]=1;
	for(int i=1;i<n;++i) T.link(in(),in());
	while(m--){
		scanf("%s",op+1),x=in(),y=in();
		if(op[1]=='Q') T.split(x,y),printf("%d\n",T.sum[y]);
		else T.split(x,y),T.Tag(y,in());
	}
	return 0;
} 

附上一年多前写的树剖代码(那时真的 \(naive\),代码好笨拙啊qwq

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct hh{
	int next,to;
}lin[maxn<<1];
struct kk{
	int left,right,num;
}a[maxn<<2];
int siz[maxn],fa[maxn],d[maxn],son[maxn],numm[maxn];
int top[maxn],seg[maxn],rev[maxn],fir[maxn],nn,n,m,ans,z,last[4][3];
char sign[maxn<<2];
inline int read()
{
	char c;
	while((c=getchar())<'0'||c>'9');
	int x=c-'0';
	while((c=getchar())>='0'&&c<='9')
	  x=x*10+c-'0';
	return x;  
}
void init(int x,int y)
{
	lin[++nn].next=fir[x];
	fir[x]=nn;
	lin[nn].to=y;
}
void dfs1(int s,int f)
{
	int u;
	siz[s]=1,d[s]=d[f]+1,fa[s]=f;
	for(int i=fir[s];i;i=lin[i].next)
	{
		u=lin[i].to;
		if(u!=f){
	  	dfs1(u,s);
	  	siz[s]+=siz[u];
	  	if(siz[u]>siz[son[s]]) son[s]=u;
	  }
	} 
}
void dfs2(int f)
{
	int u=son[f];
	if(u){
		seg[u]=++seg[0];
		rev[seg[0]]=u;
		top[u]=top[f];
		dfs2(u);
	}
	for(int i=fir[f];i;i=lin[i].next)
	{
		u=lin[i].to;
		if(!top[u]){
	  	seg[u]=++seg[0];
	  	rev[seg[0]]=u;
	  	top[u]=u;
	  	dfs2(u);
	  }
	}
}
void pd(int k)
{
	a[k].left=a[k<<1].left,a[k].right=a[k<<1|1].right;
	a[k].num=a[k<<1].num+a[k<<1|1].num;
	if(a[k<<1].right==a[k<<1|1].left) --a[k].num;
}
void build(int k,int l,int r)
{
	if(l==r){
		a[k].left=a[k].right=numm[rev[l]],a[k].num=1;return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid),build(k<<1|1,mid+1,r);
	pd(k);
}
void push(int k)
{
	a[k<<1].left=a[k<<1].right=a[k<<1|1].left=a[k<<1|1].right=a[k].left;
	a[k<<1].num=a[k<<1|1].num=1;sign[k]=0,sign[k<<1]=sign[k<<1|1]=1;
}
void query(int k,int l,int r,int ll,int rr)
{
	if(l>=ll&&r<=rr){
		ans+=a[k].num;
		if(l==ll) last[3][nn]=a[k].left;//fx
		if(r==rr) last[2][nn]=a[k].right;//x
		return;
	}
	if(sign[k]) push(k);
	int mid=l+r>>1;
	if(mid>=ll) query(k<<1,l,mid,ll,rr);
	if(mid<rr) query(k<<1|1,mid+1,r,ll,rr);
	if(mid>=ll&&mid<rr&&a[k<<1].right==a[k<<1|1].left) ans--; 
} 
void change(int k,int l,int r,int ll,int rr)
{
	if(l>=ll&&r<=rr){
		a[k].num=1,a[k].left=a[k].right=z,sign[k]=1;return;
	}
	if(sign[k]) push(k);
	int mid=l+r>>1;
	if(mid>=ll) change(k<<1,l,mid,ll,rr);
	if(mid<rr) change(k<<1|1,mid+1,r,ll,rr);
	pd(k);
}
void ask(int x,int y)
{
	int fx=top[x],fy=top[y];
	last[1][1]=last[1][2]=-1;
	while(fx!=fy)
	{
		if(d[fx]>d[fy]){
			nn=1,query(1,1,seg[0],seg[fx],seg[x]);
			if(last[1][1]==last[2][1]) ans--;
			last[1][1]=last[3][1];
			x=fa[fx],fx=top[x];
		}
		else{
			nn=2,query(1,1,seg[0],seg[fy],seg[y]);
			if(last[1][2]==last[2][2]) ans--;
			last[1][2]=last[3][2];
			y=fa[fy],fy=top[y];
		}
	}
	nn=2;
	if(d[x]>d[y]) swap(x,y),nn=1;
	query(1,1,seg[0],seg[x],seg[y]);
	if(last[1][nn]==last[2][nn]) ans--;
	if(last[3][nn]==last[1][3-nn]) ans--;
}
void solve(int x,int y)
{
	int fx=top[x],fy=top[y];
	while(fx!=fy){
		if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
		change(1,1,seg[0],seg[fx],seg[x]);
		x=fa[fx],fx=top[x];
	}
	if(d[x]>d[y]) swap(x,y);
	change(1,1,seg[0],seg[x],seg[y]);
}
int main()
{
	int x,y;
	char flag[5];
	n=read(),m=read();
	for(int i=1;i<=n;++i) numm[i]=read();
	for(int i=1;i<n;++i)
	{
		x=read(),y=read();
		init(x,y),init(y,x);
	}
	dfs1(1,0),seg[0]=seg[1]=rev[1]=top[1]=1,dfs2(1),build(1,1,seg[0]);
	while(m--)
	{
		scanf("%s",flag);
		if(flag[0]=='Q'){
			x=read(),y=read(),ans=0,ask(x,y),printf("%d\n",ans);
		}
		else{
			x=read(),y=read(),z=read(),solve(x,y);
		}
	}
	return 0;
}
上一篇:Cow and Snacks


下一篇:The Suspects——求联通块数量的模板题