首页 > 代码库 > 序列操作(bzoj 1858)

序列操作(bzoj 1858)

Description

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0 3 a b 询问[a, b]区间内总共有多少个1 4 a b 询问[a, b]区间内最多有多少个连续的1 对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

Input

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作="" <="" div="">

Output

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

Sample Input

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

Sample Output

5
2
6
5

HINT

对于30%的数据,1<=n, m<=1000
对于100%的数据,1<=n, m<=100000

/*
    不想写线段树,写的分块。
    维护一下每个块的左最大连续区间,右最大连续区间,最大连续区间,和几个标记(无/全0/全1/取反)。 
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define N 100010
#define M 510
using namespace std;
int a[N],bl[N],n,m,size;
int tag[M],lc0[M],rc0[M],sc0[M],lc1[M],rc1[M],sc1[M],sum[M];

void init(int i){
    tag[i]=-1;lc0[i]=rc0[i]=sc0[i]=lc1[i]=rc1[i]=sc1[i]=sum[i]=0;
    for(int j=(i-1)*size+1;j<=min(n,i*size);j++)
        if(a[j]) sum[i]++;
    int fl=0,p=0;
    for(int j=(i-1)*size+1;j<=min(n,i*size);j++){
        if(!a[j]&&!fl) lc0[i]++;
        else fl=1;
        if(!a[j]) p++;else p=0;
        sc0[i]=max(sc0[i],p);
    }
    fl=0;
    for(int j=min(n,i*size);j>(i-1)*size;j--){
        if(!a[j]&&!fl) rc0[i]++;
        else fl=1;
    }
    fl=0,p=0;
    for(int j=(i-1)*size+1;j<=min(n,i*size);j++){
        if(a[j]&&!fl) lc1[i]++;
        else fl=1;
        if(a[j]) p++;else p=0;
        sc1[i]=max(sc1[i],p);
    }
    fl=0;
    for(int j=min(n,i*size);j>(i-1)*size;j--){
        if(a[j]&&!fl) rc1[i]++;
        else fl=1;
    }
}

void pushdown(int i){
    if(tag[i]==-1) return;
    if(tag[i]==0||tag[i]==1)
        for(int j=(i-1)*size+1;j<=i*size;j++)
            a[j]=tag[i];
    else
        for(int j=(i-1)*size+1;j<=i*size;j++)
            a[j]^=1;
    tag[i]=-1;
}

void change1(int x,int y,int v){
    pushdown(bl[x]);
    for(int i=x;i<=min(y,bl[x]*size);i++) a[i]=v;
    init(bl[x]);
    for(int i=bl[x]+1;i<bl[y];i++){
        tag[i]=v;
        if(v) lc1[i]=rc1[i]=sc1[i]=sum[i]=size,lc0[i]=rc0[i]=sc0[i]=0;
        else lc1[i]=rc1[i]=sc1[i]=sum[i]=0,lc0[i]=rc0[i]=sc0[i]=size;
    }
    if(bl[x]==bl[y]) return;
    pushdown(bl[y]);
    for(int i=(bl[y]-1)*size+1;i<=y;i++) a[i]=v;
    init(bl[y]);
}

void change2(int x,int y){
    pushdown(bl[x]);
    for(int i=x;i<=min(y,bl[x]*size);i++) a[i]^=1;
    init(bl[x]);
    for(int i=bl[x]+1;i<bl[y];i++){
        if(tag[i]==-1) tag[i]=2;
        else if(tag[i]==0) tag[i]=1;
        else if(tag[i]==1) tag[i]=0;
        else tag[i]=-1;
        swap(lc0[i],lc1[i]);swap(rc0[i],rc1[i]);
        swap(sc0[i],sc1[i]);sum[i]=size-sum[i];
    }
    if(bl[x]==bl[y]) return;
    pushdown(bl[y]);
    for(int i=(bl[y]-1)*size+1;i<=y;i++) a[i]^=1;
    init(bl[y]);
}

int query1(int x,int y){
    int ans=0;
    pushdown(bl[x]);
    for(int i=x;i<=min(y,bl[x]*size);i++)
        if(a[i]) ans++;
    for(int i=bl[x]+1;i<bl[y];i++) ans+=sum[i];
    if(bl[x]==bl[y]) return ans;
    pushdown(bl[y]);
    for(int i=(bl[y]-1)*size+1;i<=y;i++)
        if(a[i]) ans++;
    return ans;
}

int query2(int x,int y){
    int ans=0,l=0;
    pushdown(bl[x]);
    for(int i=x;i<=min(y,bl[x]*size);i++){
        if(a[i]) l++;else l=0;
        ans=max(ans,l);
    }
    for(int i=bl[x]+1;i<bl[y];i++){
        l+=lc1[i];
        ans=max(ans,l);
        ans=max(ans,sc1[i]);
        if(lc1[i]!=size) l=rc1[i];
    }
    if(bl[x]==bl[y]) return max(ans,l);
    pushdown(bl[y]);
    for(int i=(bl[y]-1)*size+1;i<=y;i++){
        if(a[i]) l++;else l=0;
        ans=max(ans,l);
    }
    return ans;
}

int main(){
    memset(tag,-1,sizeof(tag));
    scanf("%d%d",&n,&m);size=sqrt(n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        bl[i]=(i-1)/size+1;
    }
    for(int i=1;i<=bl[n];i++) init(i);
    int op,x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&op,&x,&y);x++;y++;
        if(op==0) change1(x,y,0);
        if(op==1) change1(x,y,1);
        if(op==2) change2(x,y);
        if(op==3) printf("%d\n",query1(x,y));
        if(op==4) printf("%d\n",query2(x,y));
    }
    return 0;
}

 

序列操作(bzoj 1858)