AT_abc341_e [ABC341E] Alternating String 题解

题目

题目链接

题意简述:给你一个字符串,定义 \(0\)\(1\) 交错排序的字符串为好串。现在有两个操作,操作一为反转区间的 \(0\)\(1\),即 \(0\)\(1\)\(1\)\(0\),操作二为查询区内的字符串是否为好串。

分析

简单的线段树,不用动脑子,最喜欢这样的线段树啦!

一眼想到线段树,那我们就用线段树来做吧。对于查询操作我们需要维护一个串是否是好串。对于修改操作,我们维护的东西就有点多了。

  1. 首先我们维护一下反转了这个区间几次。
  2. 然后我们维护一下区间左端点和右端点是 \(0\) 还是 \(1\),方便进行合并操作。

我们考虑如何合并。如果一个区间的子区间有一个不是好串,显而易见这个大区间也不可能是好串。如果子区间都是好串,并且左区间的右端点不等于右区间的左端点那么这个大区间就是好串,否则就不是。

考虑如何下传懒标记。对于一个有懒标的大区间,如果它被反转了偶数次,其实就是反转回来了,我们不需要操作。如果反转了奇数词,那么我们就下传懒标。显而易见,反转操作并不会让子区间的好串变成不好的串,也不会让不好的串变成好串,所以我们只需要改变一下子区间的左端点和右端点的值即可。

代码

我通过异或来维护反转了几次,用异或来计算左右端点的值。

#include <bits/stdc++.h>
using namespace std;

const int N = 5e5+10;

int n , m;
int w[N];

struct node 
{
	int l , r;
	int ll , rr;
	bool check;
	int inv;
}tr[N<<2];

void pushup (int u)
{
	tr[u].ll = tr[u<<1].ll , tr[u].rr = tr[u<<1|1].rr;
	if (tr[u<<1].rr!=tr[u<<1|1].ll && tr[u<<1].check && tr[u<<1|1].check)
	{
		tr[u].check = 1;
	}
	else 
	{
		tr[u].check = 0;
	}
}

void pushdown (int u)
{
	if (tr[u].inv)
	{
		tr[u<<1].ll ^= 1 , tr[u<<1].rr ^= 1 , tr[u<<1].inv ^= 1;
		tr[u<<1|1].ll ^= 1 , tr[u<<1|1].rr ^= 1 , tr[u<<1|1].inv ^= 1;
		tr[u].inv = 0;
	}
}

void build (int u , int l , int r)
{
	if (l==r)
	{
		tr[u] = {l , r , w[l] , w[l] , 1 , 0};
	}
	else 
	{
		tr[u] = {l , r};
		int mid = (l+r)>>1;
		build (u<<1 , l , mid) , build (u<<1|1 , mid+1 , r);
		pushup (u);
	}
}

void modify (int u , int l , int r)
{
	if (tr[u].l>=l && tr[u].r<=r)
	{
		tr[u].inv ^= 1;
		tr[u].ll^=1 , tr[u].rr^=1;
		return;
	}
	pushdown (u);
	int mid = (tr[u].l+tr[u].r)>>1;
	if (l<=mid)
	{
		modify (u<<1 , l , r);
	}
	if (r>mid)
	{
		modify (u<<1|1 , l , r);
	}
	pushup(u);
}

bool query (int u , int l , int r)
{
	if (tr[u].l>=l && tr[u].r<=r)
	{
		return tr[u].check;
	}
	pushdown (u);
	int mid = (tr[u].l+tr[u].r)>>1;
	bool res = 1;
	if (l<=mid)
	{
		res &= query (u<<1 , l , r);
		if (r>mid)
		{
			res &= query (u<<1|1 , l , r);
			if (tr[u<<1].rr==tr[u<<1|1].ll)
			{
				res = 0;
			}		
		}
	}
	else if (r>mid)
	{
		res &= query (u<<1|1 , l , r);
	}
	return res;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	
	cin >> n >> m;
	string s;
	cin >> s;
	for (int i=0 ; i<s.size() ; i++)
	{
		w[i+1] = s[i]-'0';
	}
	
	build (1 , 1 , n);
	
	while (m--)
	{
		int op , l , r;
		cin >> op >> l >> r;
		if (op==1)
		{
			modify (1 , l , r);
		}
		else 
		{
			if (query (1 , l , r))
			{
				cout << "Yes" << endl;
			}
			else 
			{
				cout << "No" << endl;
			}
		}
	}
	return 0;
}

posted @ 2024-02-22 19:09  hh20080501hh  阅读(18)  评论(0)    收藏  举报