P4979 矿洞:坍塌 题解
开一棵线段树,区间内合并左右儿子的时候,如果颜色相同则赋成此颜色,否则直接赋成 \(0\),第三个操作只需要区间 \([l,r]\) 答案不为 \(0\) 且两边颜色不一样即可。比较简单,复杂度 \(O(n\log n)\)。
点击查看代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N=5e5+13;
int n,m;char in[N];
struct SegTree{int l,r,dat,set;}t[N<<2];
#define ls p<<1
#define rs p<<1|1
#define mid ((t[p].l+t[p].r)>>1)
inline void refresh(int p){t[p].dat=(t[ls].dat==t[rs].dat?t[ls].dat:0);}
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){t[p].dat=in[l]-'A'+1;return;}
build(ls,l,mid),build(rs,mid+1,r);
refresh(p);
}
inline void pushup(int p,int x){t[p].dat=t[p].set=x;}
inline void pushdown(int p){
if(!t[p].set) return;
pushup(ls,t[p].set),pushup(rs,t[p].set);
t[p].set=0;
}
void update(int p,int l,int r,int x){
if(l<=t[p].l&&t[p].r<=r) return pushup(p,x);
pushdown(p);
if(l<=mid) update(ls,l,r,x);
if(r>mid) update(rs,l,r,x);
refresh(p);
}
int query(int p,int l,int r){
if(l<=t[p].l&&t[p].r<=r) return t[p].dat;
pushdown(p);
if(r<=mid) return query(ls,l,r);
if(l>mid) return query(rs,l,r);
int lc=query(ls,l,r),rc=query(rs,l,r);
return lc==rc?lc:0;
}
#undef ls
#undef rs
#undef mid
int main(){
scanf("%d%s",&n,in+1);
build(1,1,n);
scanf("%d",&m);
while(m--){
int l,r;char op,c;
cin>>op;scanf("%d%d",&l,&r);
if(op=='A') cin>>c,update(1,l,r,c-'A'+1);
else puts(query(1,l,r)&&(l==1||r==n||query(1,l-1,l-1)!=query(1,r+1,r+1))?"Yes":"No");
}
return 0;
}