(线段树,01序列)[ABC341E] Alternating String题解

题意

给定一个 0101 字符串 SS,定义相邻字符均不同的字符串为好串,要求支持两种操作。

  • 1 L R,将从 LLRR 的区间取反。

  • 2 L R,查询 SSLLRR 的子串是否为好串。

分析

没有接触过这种题的建议去看一眼 P6492

比较板子,对于这种题,一般都是去维护区间的两个端点。

一个区间左儿子的左端点便是这个区间的左端点,一个区间右儿子的右端点便是这个区间的右端点。

合并的话,首先要考虑拼接处的左右儿子是否是好串,其次要考虑拼接处两个端点的字符是否不同,最后 pushdown 的时候记得取反就可以了。

线段树相比其他做法代码冗长,常数也大,但是逻辑相对简单,好想好写。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int n,q,a[maxn];
struct node {
	int l,r;
	bool ans;
	int pre,suf;
	int tag;
} t[maxn*4];
void pushup(int p) {
	t[p].ans=(t[p*2].ans && t[p*2+1].ans && (t[p*2].suf!=t[p*2+1].pre));
	t[p].pre=t[p*2].pre;
	t[p].suf=t[p*2+1].suf;
}
void pushdown(int p) {
	if(t[p].tag) {
		t[p*2].tag^=1;
		t[p*2+1].tag^=1;
		t[p*2].pre= !t[p*2].pre;
		t[p*2].suf= !t[p*2].suf;
		t[p*2+1].pre= !t[p*2+1].pre;
		t[p*2+1].suf= !t[p*2+1].suf;
		t[p].tag=0;
	}
}
void build(int p,int l,int r) {
	t[p].l=l,t[p].r=r;
	t[p].tag=0;
	if(l==r) {
		t[p].ans=1;
		t[p].pre=t[p].suf=a[l];
		return;
	}
	int mid=(l+r)/2;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	pushup(p);
}
void change(int p,int l,int r) {
	if(r<t[p].l or t[p].r<l)
		return;
	if(l<=t[p].l && t[p].r<=r) {
		t[p].tag^=1;
		t[p].pre= !t[p].pre;
		t[p].suf= !t[p].suf;
		return;
	}
	pushdown(p);
	change(p*2,l,r);
	change(p*2+1,l,r);
	pushup(p);
}
bool cmp(node a,node b) {
	return (a.ans && b.ans && a.suf!=b.pre);
}
int check1(node a,node b) {
	if(a.pre==-1)
		return b.pre;
	return a.pre;
}
int check2(node a,node b) {
	if(b.suf==-1)
		return a.suf;
	return b.suf;
}
node ask(int p,int l,int r) {
	if(r<t[p].l or t[p].r<l)
		return {-1,-1,1,-1,-1,-1};
	if(l<=t[p].l && t[p].r<=r)
		return t[p];
	pushdown(p);
	node a=ask(p*2,l,r),b=ask(p*2+1,l,r);
	return {-1,-1,cmp(a,b),check1(a,b),check2(a,b),-1};
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>q;
	for(int i=1; i<=n; i++) {
		char ch;
		cin>>ch;
		a[i]=ch-'0';
	}
	build(1,1,n);
	while(q--) {
		int op,l,r;
		cin>>op>>l>>r;
		if(op==1)
			change(1,l,r);
		if(op==2) {
			if(ask(1,l,r).ans)
				cout<<"Yes\n";
			else
				cout<<"No\n";
		}
	}
	return 0;
}
posted @ 2024-02-19 13:43  p7gab  阅读(0)  评论(0编辑  收藏  举报  来源