NC20279序列操作

在这里插入图片描述
输入:
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;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_53688600/article/details/114449640
nc