输入:
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
输出:
5
2
6
5
思路: 核心:线段树、模拟
首先确定要维护的信息,要查区间1的数量,最大连续1的长度,又有取反操作(0和1信息交换)。
所以最好0和1的信息都要维护。对于0和1我开了个数组分别存信息,因为对0和1的操作类似,用个for(0->1)少写点代码~
维护区间0和1的数量,最大连续0和1的长度。
连续长度可能还有出现在区间合并中,所以还要维护区间两端的0和1向中间连续扩展的长度。
还有一些说明在代码注释中谈及。
记得向下传递lazy标记时,消除自身lazy标记!!!
(挺麻烦的一道线段树×
#include <bits/stdc++.h>
#define IOS std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
using namespace std;
typedef long long ll;
const int N=100100;
struct ty //线段树维护的量
{
int lazy; //0全为0 1全为1 2取反 3没有操作
int l[2],r[2]; //左右连续的01
int max[2]; //最大连续01
int cnt[2]; //01的数量
}tree[4*N];
int a[N];
void pushup(int p, int l, int r)
{
int mid = (l + r)/ 2;
for (int i = 0; i <= 1; i++)
{
tree[p].cnt[i] = tree[p*2].cnt[i] + tree[p*2+1].cnt[i];
tree[p].max[i] = max(max(tree[p*2].max[i], tree[p*2+1].max[i]),
tree[p*2].r[i]+tree[p*2+1].l[i]);
if (tree[p*2].l[i] == (mid-l+1)) tree[p].l[i] = tree[p*2].l[i]+ tree[p*2+1].l[i];
else tree[p].l[i] = tree[p*2].l[i];
if (tree[p*2+1].r[i] ==(r-(mid+1)+1)) tree[p].r[i] = tree[p*2+1].r[i] + tree[p*2].r[i];
else tree[p].r[i] = tree[p*2+1].r[i];
}
}
void build(int p, int l ,int r)
{
tree[p].lazy = 3;
if(l == r) {
tree[p].cnt[a[l]] = 1;
tree[p].max[a[l]] = 1;
tree[p].l[a[l]] = 1;
tree[p].r[a[l]] = 1;
return ;
}
int mid = (l+r)/ 2;
build(p *2, l, mid);
build(p *2+1, mid+1, r);
pushup(p, l, r);
}
void pushdown(int p, int l, int r)
{
int mid=( l+r)>>1;
int x=tree[p].lazy;
if( x<=1) //如果是操作0和操作1
{
//左子树
tree[2*p].lazy = x;
tree[2*p].cnt[x] = tree[2*p].max[x] = tree[2*p].l[x] = tree[2*p].r[x] = mid-l+1;
tree[2*p].cnt[x^1] = tree[2*p].max[x^1] = tree[2*p].l[x^1] = tree[2*p].r[x^1] = 0;
tree[2*p+1].lazy = x;
tree[2*p+1].cnt[x] = tree[2*p+1].max[x] = tree[2*p+1].l[x] = tree[2*p+1].r[x] = r-(mid+1)+1;
tree[2*p+1].cnt[x^1] = tree[2*p+1].max[x^1] = tree[2*p+1].l[x^1] = tree[2*p+1].r[x^1] = 0;
//传完标记,消除父亲标记!!!
tree[p].lazy=3;
}
else
{
tree[2*p].lazy^=1;
swap(tree[2*p].cnt[0],tree[2*p].cnt[1] );
swap(tree[2*p].max[0],tree[2*p].max[1] );
swap(tree[2*p].l[0],tree[2*p].l[1] );
swap(tree[2*p].r[0],tree[2*p].r[1] );
tree[2*p+1].lazy^=1;
swap(tree[2*p+1].cnt[0],tree[2*p+1].cnt[1] );
swap(tree[2*p+1].max[0],tree[2*p+1].max[1] );
swap(tree[2*p+1].l[0],tree[2*p+1].l[1] );
swap(tree[2*p+1].r[0],tree[2*p+1].r[1] );
//传完标记,消除父亲标记!!!
tree[p].lazy=3;
}
}
void change(int p,int l, int r,int a, int b ,int x) //区级修改,操作01
{
//如果区间覆盖
if( a <= l && r <= b )
{
tree[p].lazy = x;
tree[p].cnt[x] = tree[p].max[x] = tree[p].l[x] = tree[p].r[x] = r-l+1;
tree[p].cnt[x^1] = tree[p].max[x^1] = tree[p].l[x^1] = tree[p].r[x^1] = 0;
return ;
}
if( tree[p].lazy != 3) pushdown(p,l,r);
int mid=(l+r)>>1;
if( a <= mid ) change(2*p ,l, mid ,a ,b,x);
if( b > mid ) change(2*p+1 ,mid+1,r, a ,b ,x);
pushup(p,l,r);
}
void revers(int p, int l, int r, int a ,int b)
{
if( a <= l && r <= b)
{
tree[p].lazy^=1;
swap(tree[p].cnt[0],tree[p].cnt[1] );
swap(tree[p].max[0],tree[p].max[1] );
swap(tree[p].l[0],tree[p].l[1] );
swap(tree[p].r[0],tree[p].r[1] );
return ;
}
int mid=(l+r)>>1;
if( tree[p].lazy!=3 ) pushdown(p,l,r);
if( a <= mid ) revers(2*p ,l, mid ,a ,b);
if( b > mid ) revers(2*p+1 ,mid+1,r, a ,b);
pushup(p,l,r);
}
int findsum(int p,int l,int r,int x, int y)
{
if( x<=l && r<=y ) return tree[p].cnt[1];
int mid=(l+r)>>1;
ll res=0;
if( tree[p].lazy!=3 ) pushdown(p,l,r);
if( x<=mid ) res+=findsum(2*p ,l ,mid,x,y);
if( y>mid ) res+=findsum(2*p+1 ,mid+1 ,r,x,y);
return res;
}
struct ty2
{
int mx, l, r;
};
ty2 findmax(int p , int l, int r, int a, int b)
{
ty2 ans;
if (a <= l && r <= b)
{
ans.mx = tree[p].max[1];
ans.l= tree[p].l[1];
ans.r= tree[p].r[1];
return ans;
}
int mid = (l+r)/2;
if (tree[p].lazy != 3) pushdown(p, l, r);
if (b <= mid) return findmax(p*2, l, mid, a, b);
if (a > mid) return findmax(p*2+1, mid+1, r, a, b);
ty2 left = findmax(p*2, l, mid, a, mid);
ty2 right = findmax(p*2+1, mid+1, r, mid+1, b);
ans.mx = max(max(left.mx, right.mx),left.r+right.l);
if (left.l == (mid-l+1)) ans.l = left.l+right.l;
else ans.l = left.l;
if (right.l == (r-(mid+1)+1)) ans.r = left.r+right.r;
else ans.r = right.r;
return ans;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1 ;i<=n ;i++)
cin>>a[i];
//建树
build(1,1,n);
for(int i=1 ;i<=m ;i++)
{
int op,x,y;
cin>>op>>x>>y;
x++,y++;
if(op <= 1)
change(1,1,n,x,y,op);
if(op == 2)
revers(1,1,n,x,y);
if(op == 3)
cout<<findsum(1,1,n,x,y)<<endl;
if(op == 4)
cout<<findmax(1,1,n,x,y).mx<<endl;
}
}