[SDOI2011] 染色

[SDOI2011] 染色 (树链剖分)

题意:

给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种:

1.将节点 a 到节点 b 的路径上的所有点(包括 a 和 b )都染成颜色 c。
opt == 'C'
2.询问节点 a 到节点 b 的路径上的颜色段数量。
opt == 'Q'

颜色段的定义是极长的连续相同颜色被认为是一段。例如 112221 由三段组成:11、222、1。


思路:

本题主要思路已经被讲得非常清楚

我提供 求路径上颜色段 の another way

见代码:

int asksum(int p,int l,int r,int askl,int askr,int &tls,int &trs) {
	if(askl<=l && r<=askr) {
		tls=ls[p]; trs=rs[p];
		return sum[p];
	}
	pushdown(p);
	int mid=(l+r)>>1;
	bool pl=false,pr=false;
	int l1=0,r1=0,l2=0,r2=0,res=0;
	if(askl<=mid) {
		pl=true;
		res+=asksum(p<<1,l,mid,askl,askr,l1,r1);
	}
	if(mid<askr) {
		pr=true;
		res+=asksum(p<<1|1,mid+1,r,askl,askr,l2,r2);
	}


	if(pl==true && pr==true) {
		if(r1==l2) res--;
		tls=l1; trs=r2;		
	}
	else if(pl==true) {
		tls=l1; trs=r1;		
	}
	else if(pr==true) {
		tls=l2; trs=r2;			
	}


	return res;
}

int ask(int x,int y) {
	int lca=getlca(x,y);
	int ll,rr,last1=0,last2=0,res1=0,res2=0,res=0;


	while(top[x]!=top[lca]) {
		ll=0; rr=0;
		res1+=asksum(1,1,n,dfn[top[x]],dfn[x],ll,rr);
		if(!last1) last1=ll;
		else res1=res1-(rr==last1),last1=ll;
		x=fa[top[x]];
	}
	if(lca!=x) {
		ll=0; rr=0;
		res1+=asksum(1,1,n,dfn[lca]+1,dfn[x],ll,rr);
		if(last1) res1=res1-(rr==last1);
		last1=ll;
	}

	
	while(top[y]!=top[lca]) {
		ll=0; rr=0;
		res2+=asksum(1,1,n,dfn[top[y]],dfn[y],ll,rr);
		if(!last2) last2=ll;
		else res2=res2-(rr==last2),last2=ll;
		y=fa[top[y]];
	}
	ll=0; rr=0;
	res2+=asksum(1,1,n,dfn[lca],dfn[y],ll,rr);
	if(last2) res2=res2-(rr==last2);	
	last2=ll;

	
	res=res1+res2-(last1==last2);
	return res;
}

对于上方的路径,我们将其分为green和blue两部分路径,对它们分别统计颜色数:

这两条路径,每一条会被不同的重轻链分割成很多部分

每个部分对应线段树上の一个区间

将这些区间合并时,要记录区间左右端点的颜色是什么

我选择在查找的时候记录它们(使用 asksum(......int &tls,int &trs) )

用 last1 (green part) 和 last2 (blue part) 记录上一个区间的左端点,并拿它与当前区间的右端点作比较

若二者相同,则res--,反之res不变


green and blue parts统计完成后,将last1与last2作比较,相同则res--,反之res不变

最后输出res即可

posted on 2024-11-04 19:48  Ueesugi_sakura  阅读(2)  评论(0编辑  收藏  举报