1. 程式人生 > 其它 >P4979 礦洞:坍塌 題解

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;
}