F - Vacation Query

发布时间 2023-10-01 17:12:32作者: 不o凡

F - Vacation Query

此题与4301 Can you answer on these queries III类似
只不过要维护0和1两个值
解法:
区间修改和查询,可以利用线段树
1.两区间合并的答案,要么lc(左子树)中,要么在rc(右子树)中,但是也有可能出现在(lc的右端点连续的1加上rc左端点连续的1),所以要多维护两个数据lmx(左端点的最大连续1),rmx(右端点的最大连续1);

2.对于修改操作,我们发现其实是把区间内0,1反转了,所以我们可以利用二维数组分别维护0,1的ans,lmx,rmx,修改时直接交换就好

总结:一道很经典的模板题

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 5e5 + 10;
int a[N];

//线段树
#define lc k<<1
#define rc k<<1|1
struct tree {
	int l, r;
	int ans[2],lmx[2],rmx[2];
	int lz;
}tr[N*4];
void pushup(tree& u, tree ll, tree rr) {//合并区间
	//ans
	u.ans[0] = max(ll.ans[0], max(rr.ans[0], ll.rmx[0] + rr.lmx[0]));
	u.ans[1] = max(ll.ans[1], max(rr.ans[1], ll.rmx[1] + rr.lmx[1]));
	//lmx
	u.lmx[0] = ll.lmx[0];
	if (ll.lmx[0] == (ll.r - ll.l + 1)) u.lmx[0] += rr.lmx[0];
	u.lmx[1] = ll.lmx[1];
	if (ll.lmx[1] == (ll.r - ll.l + 1)) u.lmx[1] += rr.lmx[1];
	//rmx
	u.rmx[0] = rr.rmx[0];
	if (rr.rmx[0] == (rr.r - rr.l + 1)) u.rmx[0] += ll.rmx[0];
	u.rmx[1] = rr.rmx[1];
	if (rr.rmx[1] == (rr.r - rr.l + 1)) u.rmx[1] += ll.rmx[1];
}
void build(int k, int l, int r) {
	tr[k] = { l,r };
	if (l == r) {
		if (a[l] == 0) {
			tr[k].rmx[0]=tr[k].lmx[0]=tr[k].ans[0] = 1;
		}
		else {
			tr[k].rmx[1] = tr[k].lmx[1] = tr[k].ans[1] = 1;
		}
		return;
	}
	int mid = l + r >> 1;
	build(lc, l, mid); build(rc, mid + 1, r);
	pushup(tr[k],tr[lc],tr[rc]);
}
void swap_(int k) {
	swap(tr[k].ans[0], tr[k].ans[1]);
	swap(tr[k].lmx[0], tr[k].lmx[1]);
	swap(tr[k].rmx[0], tr[k].rmx[1]);
}
void pushdown(int k) {
	if (tr[k].lz) {
		swap_(lc), swap_(rc);
		tr[lc].lz ^= 1;
		tr[rc].lz ^= 1;
		tr[k].lz ^= 1;
	}
}
void modify(int k, int l, int r) {//区间修改
	if (tr[k].l >= l && tr[k].r <= r) {
		swap_(k);//相当于维护的01交换了
		tr[k].lz ^= 1;//懒标记
		return;
	}
	pushdown(k);
	int mid = tr[k].l + tr[k].r >> 1;
	if (l <= mid) modify(lc, l, r);
	if(r>mid) modify(rc, l, r);//千万不要写成单点修改
	pushup(tr[k], tr[lc], tr[rc]);
}

tree query(int k, int l, int r) {
	if (tr[k].l >= l && tr[k].r <= r) return tr[k];
	pushdown(k);
	int mid = tr[k].l + tr[k].r >> 1;
	if (mid >= r) return query(lc, l, r);
	if (mid < l) return query(rc, l, r);
	tree T;//临时变量
	pushup(T, query(lc, l, mid), query(rc, mid+1, r));//区间合并
	return T;
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	int n, q;
	cin >> n >> q;
	string s;
	cin >> s;
	for (int i = 1; i <= n; i++) a[i] = s[i-1] - '0';
	build(1, 1, n);
	while (q--) {
		int op,l,r;
		cin >> op>>l>>r;
		if (op == 1) {
			modify(1, l, r);
		}
		else {
			cout << query(1, l, r).ans[1]<< '\n';
		}
	}
	return 0;
}