E. Nezzar and Binary String(逆向思维+线段树)

题目

思路:从逆向想一下,发现最后得到的一定是最后的字符串f,然后往前推,因为只能改变<len/2的元素,不难发现改变已经定下来了,即只能全改为数量大的那个字符,如果长度为偶数两种字符相等则不能达成。维护和查找用线段树覆盖。

down的一个修改
在这里插入图片描述
Code:

#include<iostream>
#define FAST ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
using namespace std;

struct node
{
	ll l, r, f, w;
}tree[5000005];

inline void build(int k, int ll, int rr)
{
	tree[k].l = ll, tree[k].r = rr, tree[k].f = -1;
	if (tree[k].l == tree[k].r) { char ch;cin >> ch;tree[k].w=ch-'0'; return; }
	int mid = (tree[k].l + tree[k].r) / 2;
	build(2 * k, ll, mid);
	build(2 * k + 1, mid + 1, rr);
	tree[k].w = tree[2 * k].w + tree[2 * k + 1].w;
}

inline void down(int k)
{
	if (tree[k].f == -1)return;//表示此时f为无效状态
	tree[2 * k].f = tree[k].f;
	tree[2 * k + 1].f = tree[k].f;
	tree[2 * k].w = tree[k].f * (tree[2 * k].r - tree[2 * k].l + 1);//直接让后面的值等于f
	tree[2 * k + 1].w = tree[k].f * (tree[2 * k + 1].r - tree[2 * k + 1].l + 1);
	tree[k].f = -1;//给儿子赋值后再变为无效状态
}

inline ll ask_interval(int k, int x, int y)
{
	ll ans = 0;
	if (x <= tree[k].l && y >= tree[k].r)
	{
		return tree[k].w;
	}
	down(k);
	int mid = (tree[k].l + tree[k].r) / 2;
	if (x <= mid)ans += ask_interval(2 * k, x, y);
	if (y > mid)ans += ask_interval(2 * k + 1, x, y);
	return ans;
}

inline void change_interval(int k, int x, int y, int add)
{
	if (x <= tree[k].l && y >= tree[k].r)
	{
		tree[k].w = add * (tree[k].r - tree[k].l + 1);
		tree[k].f = add;
		return;
	}
	down(k);
	int mid = (tree[k].l + tree[k].r) / 2;
	if (x <= mid)change_interval(2 * k, x, y, add);
	if (y > mid)change_interval(2 * k + 1, x, y, add);
	tree[k].w = tree[2 * k].w + tree[2 * k + 1].w;
}
const int Max = 1e6 + 5;
int a[Max], b[Max], q[Max][2];

int main()
{
	FAST;
	int t;cin >> t;
	while (t--)
	{
		int n, qq;cin >> n >> qq;
		for (int i = 1;i <= n;i++)
		{
			char c;cin >> c;
			a[i] = c - '0';
		}
		build(1, 1, n);
		for (int i = 1;i <= qq;i++)cin >> q[i][0] >> q[i][1];
		int f = 1;
		for (int i = qq;i >=1 ;i--)
		{
			int l = q[i][0], r = q[i][1];
			int sum = ask_interval(1, l, r);
			if ((r - l+1) % 2 == 0 && sum == (r - l + 1) / 2) {
				f = 0;
			}
			if (sum <= (r - l + 1) / 2)change_interval(1, l, r, 0);
			else change_interval(1, l, r, 1);
		}
		for (int i = 1;i <= n;i++)
		{
			int g = ask_interval(1, i, i);
			if (a[i] != g)f = 0;
		}
		if (f)cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Rikka_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值