P4979 矿洞:坍塌

题目大意:

一个区间有若干颜色,有两个操作:

A. 将该区间从 xy 变成 k 色。

B. 询问区间 xy 是否合法。

  • 合法定义为该区间颜色均相同且 x-1 的颜色与 y+1 的颜色不相同。若 x=1y=N 时不用判断后者。

solution:

区间修改,区间查询,我们考虑使用线段树。

线段树的每个节点保存如下信息:

struct shu{
	int l,  //区间左端点
	r,    //区间右端点
	se,    /区间颜色,若不相同为-1
	tag;  //懒标记,代表要变成的颜色,初始为-1
}tr[N<<2];

颜色:这里我将 A B C 分别映射成三个数字 1 2 3

区间修改:若 x y 包含访问到的区间,则将此区间变成该颜色,并把懒标记赋值。

区间查询:若 x y 包含访问到的区间,则返回该颜色,否则递归进左右子树,合并信息:

  1. 若 询问区间不包含左区间,返回右区间的颜色。同理不包含右则返回左。
  2. 如果左右区间有一个是混色或者左右区间颜色不同返回 -1
  3. 如果左右区间颜色相同,返回该颜色。

别忘了以上操作都要 pushdown 将信息传下去。

接下来是细节的处理:

判断要格外小心。 \(\text{Yes}\) 要满足两个条件:

  1. 区间颜色相同。
  2. x==1y==nx-1 的颜色与 y+1 颜色不同,三者满足其一。

否则是 \(\text{No}\)

PS:注意 YesNo的大小写。

看到这的同学,可以自己去写代码了(tf口吻)

代码
#include<cstdio>
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int N=500005;
char s[N]; int n;
struct shu{
	int l,r,se,tag;
}tr[N<<2];
int col(char k){return k-'A'+1;}
inline void pushup(int u){
	tr[u].se=tr[ls].se==tr[rs].se?tr[ls].se:-1;
}
inline void pushdown(int u){
	if(tr[u].tag!=-1){
		tr[ls].se =tr[u].tag,tr[rs].se =tr[u].tag;
		tr[ls].tag=tr[u].tag,tr[rs].tag=tr[u].tag;
		tr[u].tag=-1;
	}
}
inline void build(int u,int l,int r){
	tr[u].l=l,tr[u].r=r,
	tr[u].tag=-1;
	if(l==r){
		tr[u].se=col(s[l-1]);
		return ;
	}
	int mid=l+r>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(u);
}
inline void gai(int u,int x,int y,int se){
	int l=tr[u].l,r=tr[u].r;
	if(x<=l&&r<=y){
		tr[u].se=se,tr[u].tag=se;
		return ;
	}
	pushdown(u);
	int mid=l+r>>1;
	if(x<=mid) gai(ls,x,y,se);
	if(y> mid) gai(rs,x,y,se);
	pushup(u);
}
inline int se(int u,int x,int y){
	if(x==0||x==n+1) return 0;
	int l=tr[u].l,r=tr[u].r; 
	if(x<=l&&r<=y) return tr[u].se;
	pushdown(u);
	int mid=l+r>>1,zuo=0,you=0;
	if(x<=mid) zuo=se(ls,x,y);
	if(y>mid ) you=se(rs,x,y);
	if(zuo==0) return you;
	if(you==0) return zuo;
	if(zuo==-1||you==-1) return -1;
	if(zuo==you) return zuo;
	return -1;
}
int main(){
	scanf("%d",&n);
	scanf("%s",s);
	build(1,1,n);
	int k; scanf("%d",&k);
	while(k--){
		char op[2],cai[2]; int x,y;
		scanf("%s",op); scanf("%d%d",&x,&y);
		
		if(op[0]=='A'){
			scanf("%s",cai);
			gai(1,x,y,col(cai[0]));
		}
		else{
			int l=se(1,x-1,x-1),r=se(1,y+1,y+1);
			//printf("%d %d\n",l,r);
			if(se(1,x,y)!=-1&&(l!=r||!l||!r))
				printf("Yes\n");
			else printf("No\n");
		}
	}
}

End