其他分享
首页 > 其他分享> > 洛谷 P2486 [SDOI2011]染色

洛谷 P2486 [SDOI2011]染色

作者:互联网

链接:

P2486

题意:

给出一棵树,节点有颜色,需要支持树链覆盖颜色,树链查询颜色段。

分析:

因为是树链操作所以考虑树链剖分,考虑在线段树上维护三个信息:当前区间最左端颜色,当前区间最右端颜色,当前区间颜色段数。pushup 时最前两个直接继承,颜色段是左右颜色段相加,同时判断左右区间中间相连部分的颜色,相同则颜色段数要减 1。线段树上查询时要开个结构体同时返回三种信息。在查询树链中,跳链时也要进行和 pushup 类似的判断。其他地方与模板区别不大。细节较多。

代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
	int p=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
	return p*f;
}
const int N=1e5+5;
int n,m,r;
int w[N];
struct egde{
	int v,next;
}e[N<<1];
int head[N],en;
void insert(int u,int v){
	e[++en].v=v;
	e[en].next=head[u];
	head[u]=en;
}
int fa[N],dep[N],size[N],hson[N],top[N],ttol[N],ltot[N],tot;
void dfs1(int u,int f){
	fa[u]=f;dep[u]=dep[f]+1;size[u]=1;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].v;
		if(v==f)continue;
		dfs1(v,u);
		size[u]+=size[v];
		if(size[v]>size[hson[u]])
			hson[u]=v;
	}	
}
void dfs2(int u,int tp){
	top[u]=tp;
	ttol[u]=++tot;
	ltot[tot]=u;
	if(hson[u])dfs2(hson[u],tp);
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].v;
		if(v==fa[u]||v==hson[u])continue;
		dfs2(v,v);
	}
}
int sum[N<<2],tag[N<<2],lc[N<<2],rc[N<<2];
inline void pushup(int p){
	sum[p]=sum[p<<1]+sum[p<<1|1]-(rc[p<<1]==lc[p<<1|1]);
	lc[p]=lc[p<<1];
	rc[p]=rc[p<<1|1];
}
inline void f(int p,int d){
	sum[p]=1;
	tag[p]=d;
	lc[p]=rc[p]=d;
}
inline void pushdown(int l,int r,int p){
	if(tag[p]){
		int mid=(l+r)>>1;
		f(p<<1,tag[p]);
		f(p<<1|1,tag[p]);
		tag[p]=0;
	}
}
void built(int l,int r,int p){
	if(l==r){
		sum[p]=1,lc[p]=rc[p]=w[ltot[l]];
		return ;
	}
	int mid=(l+r)>>1;
	built(l,mid,p<<1);
	built(mid+1,r,p<<1|1);
	pushup(p);
}
void change(int l,int r,int p,int cl,int cr,int d){
	if(l>=cl&&r<=cr){
		f(p,d);
		return ;
	}
	pushdown(l,r,p);
	int mid=(l+r)>>1;
	if(cl<=mid)change(l,mid,p<<1,cl,cr,d);
	if(cr>mid)change(mid+1,r,p<<1|1,cl,cr,d);
	pushup(p);
}
struct ret{
	int l,r,sum;
};
ret query(int l,int r,int p,int ql,int qr){
	if(l>=ql&&r<=qr)
		return {lc[p],rc[p],sum[p]};
	pushdown(l,r,p);
	int mid=(l+r)>>1;
	if(ql<=mid&&qr>mid){
		ret t1=query(l,mid,p<<1,ql,qr),t2=query(mid+1,r,p<<1|1,ql,qr);
		return {t1.l,t2.r,t1.sum+t2.sum-(t1.r==t2.l)};
	}
	else if(ql<=mid)return query(l,mid,p<<1,ql,qr);
	else return query(mid+1,r,p<<1|1,ql,qr);
}
void changeit(int x,int y,int d){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		change(1,n,1,ttol[top[x]],ttol[x],d);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	change(1,n,1,ttol[x],ttol[y],d);
}
int queryit(int x,int y){
	int res=0,lastx=0,lasty=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]>dep[top[y]]){
			ret t=query(1,n,1,ttol[top[x]],ttol[x]);
			res+=t.sum-(t.r==lastx);
			lastx=t.l;
			x=fa[top[x]];
		}
		else{
			ret t=query(1,n,1,ttol[top[y]],ttol[y]);
			res+=t.sum-(t.r==lasty);
			lasty=t.l;
			y=fa[top[y]];			
		}
	}
	res-=(lastx==query(1,n,1,ttol[x],ttol[x]).l)+(lasty==query(1,n,1,ttol[y],ttol[y]).l);
	if(dep[x]>dep[y])swap(x,y);
	res+=query(1,n,1,ttol[x],ttol[y]).sum;
	return res;
}
signed main(){
	n=in,m=in;
	for(int i=1;i<=n;i++)
		w[i]=in;
	for(int i=1;i<n;i++){
		int u=in,v=in;
		insert(u,v);
		insert(v,u);
	}
	dfs1(1,0);
	dfs2(1,1);
	built(1,n,1);
	for(int i=1;i<=m;i++){
		char c[5];
		cin>>c;
		if(c[0]=='C'){
			int a=in,b=in,c=in;
			changeit(a,b,c);
		}
		else{
			int a=in,b=in;
			cout<<queryit(a,b)<<'\n';
		}
	}
	return 0;
}
题外话:

虽然一遍过了,但我还是不想再看到类似的题了。

标签:颜色,洛谷,int,res,top,ttol,SDOI2011,query,P2486
来源: https://www.cnblogs.com/llmmkk/p/15185582.html