洛谷P2572 [SCOI2010] 序列操作

一,题目

# [SCOI2010] 序列操作

## 题目描述

lxhgww 最近收到了一个 $01$ 序列,序列里面包含了 $n$ 个数,下标从 $0$ 开始。这些数要么是 $0$,要么是 $1$,现在对于这个序列有五种变换操作和询问操作:

- `0 l r` 把 $[l, r]$ 区间内的所有数全变成 $0$

- `1 l r` 把 $[l, r]$ 区间内的所有数全变成 $1$

- `2 l r` 把 $[l,r]$ 区间内的所有数全部取反,也就是说把所有的 $0$ 变成 $1$,把所有的 $1$ 变成 $0$

- `3 l r` 询问 $[l, r]$ 区间内总共有多少个 $1$

- `4 l r` 询问 $[l, r]$ 区间内最多有多少个连续的 $1$

对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?

## 输入格式

第一行两个正整数 $n,m$,表示序列长度与操作个数。  
第二行包括 $n$ 个数,表示序列的初始状态。  
接下来 $m$ 行,每行三个整数,表示一次操作。

## 输出格式

对于每一个询问操作,输出一行一个数,表示其对应的答案。

## 样例 #1

### 样例输入 #1

```
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
```

### 样例输出 #1

```
5
2
6
5
```

## 提示

【数据范围】  
对于 $30\%$ 的数据,$1\le n,m \le 1000$;  
对于$100\%$ 的数据,$1\le n,m \le 10^5$。

二,代码

#include<iostream>
using namespace std;
const int MAXN = 1e5 + 5;
struct TREE
{
	int SUM[2], LSUM[2], RSUM[2], MAX[2];
}tree[MAXN << 2] = { 0 };
int fir[MAXN << 2], sec[MAXN << 2], thi[MAXN << 2], arr[MAXN << 2];
int ls(int p) { return p << 1; }
int rs(int p) { return p << 1 | 1; }
void pu(TREE& p, const TREE& lsp, const TREE& rsp)
{
	for (int i = 0; i <= 1; ++i)
	{
		p.LSUM[i] = lsp.LSUM[i] + (lsp.SUM[i] + lsp.SUM[i ^ 1] == lsp.LSUM[i] ? rsp.LSUM[i] : 0);
		p.RSUM[i] = rsp.RSUM[i] + (rsp.SUM[i] + rsp.SUM[i ^ 1] == rsp.RSUM[i] ? lsp.RSUM[i] : 0);
		p.SUM[i] = lsp.SUM[i] + rsp.SUM[i];
		p.MAX[i] = max(max(rsp.MAX[i], lsp.MAX[i]), lsp.RSUM[i] + rsp.LSUM[i]);
	}
}
void at(int p, int  pl, int pr, int a, int b, int c)
{
	if (a != 0 || (sec[p] == 1 && c != 0))
	{
		tree[p].SUM[1] = tree[p].LSUM[1] = tree[p].RSUM[1] = tree[p].MAX[1] = 0;
		tree[p].SUM[0] = tree[p].LSUM[0] = tree[p].RSUM[0] = tree[p].MAX[0] = pr - pl + 1;
		sec[p] = 0, thi[p] = 0, fir[p] = 1;
	}
	else if (b != 0 || (fir[p] == 1 && c != 0))
	{
		tree[p].SUM[1] = tree[p].LSUM[1] = tree[p].RSUM[1] = tree[p].MAX[1] = pr - pl + 1;
		tree[p].SUM[0] = tree[p].LSUM[0] = tree[p].RSUM[0] = tree[p].MAX[0] = 0;
		fir[p] = 0, thi[p] = 0, sec[p] = 1;
	}
	else if (c != 0)
	{
		swap(tree[p].LSUM[0], tree[p].LSUM[1]), swap(tree[p].MAX[0], tree[p].MAX[1]);
		swap(tree[p].RSUM[0], tree[p].RSUM[1]), swap(tree[p].SUM[0], tree[p].SUM[1]);
		fir[p] = sec[p] = 0, thi[p] = (thi[p] + 1) & 1;
	}
}
void pd(int p, int pl, int pr)
{
	int mid = pl + pr >> 1;
	at(ls(p), pl, mid, fir[p], sec[p], thi[p]), at(rs(p), mid + 1, pr, fir[p], sec[p], thi[p]);
	fir[p] = sec[p] = thi[p] = 0;
}
void b(int p, int pl, int pr)
{
	if (pl == pr)
	{
		tree[p].LSUM[arr[pl]] = tree[p].MAX[arr[pl]] = tree[p].RSUM[arr[pl]] = tree[p].SUM[arr[pl]] = 1;
		tree[p].LSUM[arr[pl] ^ 1] = tree[p].MAX[arr[pl] ^ 1] = tree[p].RSUM[arr[pl] ^ 1] = tree[p].SUM[arr[pl] ^ 1] = 0;
		return;
	}
	int mid = pl + pr >> 1;
	b(ls(p), pl, mid), b(rs(p), mid + 1, pr);
	pu(tree[p], tree[ls(p)], tree[rs(p)]);
}
void ch(int p, int pl, int pr, int L, int R, int a, int b, int c)
{
	pd(p, pl, pr);
	if (L <= pl && pr <= R) { at(p, pl, pr, a, b, c); return; }
	int mid = pl + pr >> 1;
	if (L <= mid) ch(ls(p), pl, mid, L, R, a, b, c);
	if (R > mid) ch(rs(p), mid + 1, pr, L, R, a, b, c);
	ls(p), rs(p);
	pu(tree[p], tree[ls(p)], tree[rs(p)]);
}
TREE qu(int p, int pl, int pr, int L, int R)
{
	pd(p, pl, pr);
	if (L <= pl && pr <= R) { return tree[p]; }
	int mid = pl + pr >> 1;
	if (L <= mid && mid < R)
	{
		TREE ans = { 0 };
		pu(ans, qu(ls(p), pl, mid, L, R), qu(rs(p), mid + 1, pr, L, R));
		return ans;
	}
	else if (L <= mid) return qu(ls(p), pl, mid, L, R);
	else return qu(rs(p), mid + 1, pr, L, R);
}
int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) cin >> arr[i];
	b(1, 1, n);
	for (int i = 1; i <= m; ++i)
	{
		int op, x, y;
		cin >> op >> x >> y;
		if (op == 0) ch(1, 1, n, x + 1, y + 1, 1, 0, 0);
		if (op == 1) ch(1, 1, n, x + 1, y + 1, 0, 1, 0);
		if (op == 2) ch(1, 1, n, x + 1, y + 1, 0, 0, 1);
		if (op == 3) cout << qu(1, 1, n, x + 1, y + 1).SUM[1] << '\n';
		if (op == 4) cout << qu(1, 1, n, x + 1, y + 1).MAX[1] << '\n';
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值