此题与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;
}