BZOJ1858 [Scoi2010]序列操作

来源:互联网 发布:flyme解锁软件 编辑:程序博客网 时间:2024/05/17 06:29

BZOJ1858 [Scoi2010]序列操作

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)

Output

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

Sample Input
10 100 0 0 1 1 0 1 0 1 11 0 23 0 52 2 24 0 40 3 62 3 74 2 81 0 50 5 63 3 9
Sample Output
5265
HINT

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

题解

因为有取反,所以我们要维护1的最长与0的最长与区间两端1/0的长度。这样,如果为取反操作的化就1/0互换。
还有一点要注意的是求答案的时候不仅要返回区间最长,也要返回区间两端1的长度。再合并区间求最长。

#include <cstdio>#include <iostream>#include <cmath>#include <stack>#include <algorithm>#include <cstring>#include <climits>#define MAXN 100000+10using namespace std;int n,m,l0[MAXN<<2],r0[MAXN<<2],m0[MAXN<<2];int l1[MAXN<<2],r1[MAXN<<2],m1[MAXN<<2],mark[MAXN<<2],rev[MAXN<<2],num[MAXN<<2];int L[MAXN<<2],R[MAXN<<2],a[MAXN];void pushup(int rt){       l1[rt]=l1[rt<<1];r1[rt]=r1[rt<<1|1];    l0[rt]=l0[rt<<1];r0[rt]=r0[rt<<1|1];    if(l1[rt]==R[rt<<1]-L[rt<<1]+1) l1[rt]+=l1[rt<<1|1];    if(r1[rt]==R[rt<<1|1]-L[rt<<1|1]+1) r1[rt]+=r1[rt<<1];    if(l0[rt]==R[rt<<1]-L[rt<<1]+1) l0[rt]+=l0[rt<<1|1];    if(r0[rt]==R[rt<<1|1]-L[rt<<1|1]+1) r0[rt]+=r0[rt<<1];    m1[rt]=max(max(m1[rt<<1],m1[rt<<1|1]),l1[rt<<1|1]+r1[rt<<1]);    m0[rt]=max(max(m0[rt<<1],m0[rt<<1|1]),l0[rt<<1|1]+r0[rt<<1]);    num[rt]=num[rt<<1]+num[rt<<1|1];}void pushdown(int rt,int l,int r){    if(mark[rt]!=-1||rev[rt])    {           int m=(l+r)>>1;        if(l==r) return ;        else        {            if(mark[rt]!=-1)            {                mark[rt<<1]=mark[rt<<1|1]=mark[rt];                r1[rt<<1]=l1[rt<<1]=m1[rt<<1]=num[rt<<1]=mark[rt]*(m-l+1);                r1[rt<<1|1]=l1[rt<<1|1]=m1[rt<<1|1]=num[rt<<1|1]=mark[rt]*(r-m);                r0[rt<<1]=l0[rt<<1]=m0[rt<<1]=!mark[rt]*(m-l+1);                r0[rt<<1|1]=l0[rt<<1|1]=m0[rt<<1|1]=!mark[rt]*(r-m);                rev[rt<<1]=rev[rt<<1|1]=0;            }            if(rev[rt]==1)            {                num[rt<<1]=(m-l+1)-num[rt<<1];                num[rt<<1|1]=(r-m)-num[rt<<1|1];                swap(r1[rt<<1],r0[rt<<1]);                swap(r1[rt<<1|1],r0[rt<<1|1]);                swap(l1[rt<<1],l0[rt<<1]);                swap(l1[rt<<1|1],l0[rt<<1|1]);                swap(m1[rt<<1],m0[rt<<1]);                swap(m1[rt<<1|1],m0[rt<<1|1]);                rev[rt<<1]^=rev[rt];                rev[rt<<1|1]^=rev[rt];            }        }        rev[rt]=0;mark[rt]=-1;    }}void build(int rt,int l,int r){       mark[rt]=-1;L[rt]=l;R[rt]=r;    if(l==r)    {        l1[rt]=m1[rt]=r1[rt]=num[rt]=a[l];        l0[rt]=m0[rt]=r0[rt]=!a[l];        return ;    }    int m=(l+r)>>1;    build(rt<<1,l,m);    build(rt<<1|1,m+1,r);    pushup(rt);}void update(int L,int R,int c,int l,int r,int rt){    pushdown(rt,l,r);    if(L<=l&&r<=R)    {           if(c<2)        {            r1[rt]=l1[rt]=m1[rt]=num[rt]=c*(r-l+1);            r0[rt]=l0[rt]=m0[rt]=(!c)*(r-l+1);            mark[rt]=c;        }else        {            swap(r1[rt],r0[rt]);swap(l1[rt],l0[rt]);swap(m1[rt],m0[rt]);            num[rt]=(r-l+1)-num[rt];            rev[rt]^=1;        }        return ;    }    int m=(l+r)>>1;    if(L<=m) update(L,R,c,l,m,rt<<1);    if(R>m) update(L,R,c,m+1,r,rt<<1|1);    pushup(rt);}int query(int L,int R,int v,int l,int r,int rt,int &ln,int &rn){    if(L<=l&&r<=R)    {        ln=l1[rt];rn=r1[rt];        return v?m1[rt]:num[rt];    }    int m=(l+r)>>1,lans=0,rans=0,aans=0,ln1=0,rn1=0,ln2=0,rn2=0;    pushdown(rt,l,r);    if(L<=m) lans=query(L,R,v,l,m,rt<<1,ln1,rn1),aans+=rn1;    if(R>m) rans=query(L,R,v,m+1,r,rt<<1|1,ln2,rn2),aans+=ln2;    if(v)     {        ln=ln1;if(ln1==m-l+1) ln+=ln2;        rn=rn2;if(rn2==r-m) rn+=rn1;        return max(max(lans,rans),aans);    }    else return lans+rans;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    build(1,1,n);    int x,b,c,t1,t2;    for(int i=1;i<=m;i++)    {        scanf("%d%d%d",&x,&b,&c);        b++,c++;        if(x<=2) update(b,c,x,1,n,1);        else          if(x==3) printf("%d\n",query(b,c,0,1,n,1,t1,t2));        else if(x==4) printf("%d\n",query(b,c,1,1,n,1,t1,t2));    }    return 0;}
0 0