1858: [Scoi2010]序列操作

1858: [Scoi2010]序列操作
Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 3397 Solved: 1624
[Submit][Status][Discuss]
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 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,2,我们可以打三个lazy标记。注意下放的时候应该先下放0,1标记,再下放翻转标记。而更新时如果是0,1标记,要将其他标记清空。
对于操作3我们可以维护一个sum数组表示区间内1的个数,直接输出即可。对于操作4,我的做法可能比较复杂,我维护了6个数组,分别是从左向右,从右向左,整个区间的最大0/1个数(不知道的跳转spoj GSS1),为什么要维护0,因为这样翻转操作直接swap即可,代码量较大,细节较多。

代码

#include<iostream>
#include<cstdio>

using namespace std;
const int MAXN = 100005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,a[MAXN],L[MAXN<<2],R[MAXN<<2],lx0[MAXN<<2],rx0[MAXN<<2];
int lazy0[MAXN<<2],lazy1[MAXN<<2],rev[MAXN<<2],mx0[MAXN<<2];
int sum[MAXN<<2],lx1[MAXN<<2],mx1[MAXN<<2],rx1[MAXN<<2];
int ans,LX,RX,MX,SUM,LL,RR;

inline void pushdown(int x){
    if(lazy0[x]){
        lazy0[x]=sum[x<<1]=sum[x<<1|1]=0;
        lazy1[x<<1]=lazy1[x<<1|1]=0;
        rev[x<<1]=rev[x<<1|1]=0;
        lazy0[x<<1]=lazy0[x<<1|1]=1;
        lx1[x<<1]=rx1[x<<1]=mx1[x<<1]=0;
        lx1[x<<1|1]=rx1[x<<1|1]=mx1[x<<1|1]=0;
        lx0[x<<1]=rx0[x<<1]=mx0[x<<1]=R[x<<1]-L[x<<1]+1;
        lx0[x<<1|1]=rx0[x<<1|1]=mx0[x<<1|1]=R[x<<1|1]-L[x<<1|1]+1;
    }
    if(lazy1[x]){
        lazy1[x]=rev[x<<1]=rev[x<<1|1]=0;
        lazy0[x<<1]=lazy0[x<<1|1]=0;
        lazy1[x<<1]=lazy1[x<<1|1]=1;
        lx1[x<<1]=rx1[x<<1]=mx1[x<<1]=sum[x<<1]=R[x<<1]-L[x<<1]+1;
        lx0[x<<1]=rx0[x<<1]=mx0[x<<1]=0;
        lx1[x<<1|1]=rx1[x<<1|1]=mx1[x<<1|1]=sum[x<<1|1]=R[x<<1|1]-L[x<<1|1]+1;
        lx0[x<<1|1]=rx0[x<<1|1]=mx0[x<<1|1]=0;
    }
    if(rev[x]){
        rev[x]=0;rev[x<<1]^=1;rev[x<<1|1]^=1;
        swap(lx1[x<<1],lx0[x<<1]);swap(rx1[x<<1],rx0[x<<1]);
        swap(mx1[x<<1],mx0[x<<1]);swap(mx1[x<<1|1],mx0[x<<1|1]);
        swap(lx1[x<<1|1],lx0[x<<1|1]);swap(rx1[x<<1|1],rx0[x<<1|1]);
        sum[x<<1]=(R[x<<1]-L[x<<1]+1-sum[x<<1]);
        sum[x<<1|1]=(R[x<<1|1]-L[x<<1|1]+1-sum[x<<1|1]);
    }
}

inline void pushup(int x){
    sum[x]=sum[x<<1]+sum[x<<1|1];
    L[x]=L[x<<1],R[x]=R[x<<1|1];
    lx0[x]=lx0[x<<1];rx0[x]=rx0[x<<1|1];
    if(sum[x<<1]==0)
        lx0[x]=(R[x<<1]-L[x<<1]+1+lx0[x<<1|1]);
    if(sum[x<<1|1]==0)
        rx0[x]=(R[x<<1|1]-L[x<<1|1]+1+rx0[x<<1]);
    mx0[x]=max(mx0[x<<1],max(mx0[x<<1|1],rx0[x<<1]+lx0[x<<1|1]));
    lx1[x]=lx1[x<<1];rx1[x]=rx1[x<<1|1];
    if(sum[x<<1]==(R[x<<1]-L[x<<1]+1))
        lx1[x]=(R[x<<1]-L[x<<1]+1+lx1[x<<1|1]);
    if(sum[x<<1|1]==(R[x<<1|1]-L[x<<1|1]+1))
        rx1[x]=(R[x<<1|1]-L[x<<1|1]+1+rx1[x<<1]);
    mx1[x]=max(mx1[x<<1],max(mx1[x<<1|1],rx1[x<<1]+lx1[x<<1|1]));

}

inline void build(int x,int l,int r){
    if(l==r){
        sum[x]=a[l];
        L[x]=l;R[x]=r;
        if(a[l]==0)
            lx0[x]=rx0[x]=mx0[x]=1;
        else 
            lx1[x]=rx1[x]=mx1[x]=1; 
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    pushup(x);
}

inline void update(int x,int l,int r,int ql,int qr,int k){
    if(ql<=l && r<=qr){
        int kk=k;
        if(kk==2){
            rev[x]^=1;
            sum[x]=(r-l+1-sum[x]);
            swap(lx0[x],lx1[x]);swap(rx0[x],rx1[x]);
            swap(mx0[x],mx1[x]);
        }
        if(kk==0) {
            rev[x]=sum[x]=lazy1[x]=0;lazy0[x]=1;
            mx0[x]=lx0[x]=rx0[x]=r-l+1;
            mx1[x]=lx1[x]=rx1[x]=0;
        }
        if(kk==1){
            rev[x]=lazy0[x]=0;lazy1[x]=1;
            mx0[x]=lx0[x]=rx0[x]=0;
            mx1[x]=lx1[x]=rx1[x]=sum[x]=r-l+1;
        }
        return;
    }
    int mid=l+r>>1;
    pushdown(x);
    if(ql<=mid) update(x<<1,l,mid,ql,qr,k);
    if(qr>mid)  update(x<<1|1,mid+1,r,ql,qr,k);
    pushup(x);
}

inline int query1(int x,int l,int r,int ql,int qr){
    if(ql<=l && r<=qr) return sum[x];
    int mid=l+r>>1;
    pushdown(x);
    int ret=0;
    if(ql<=mid) ret+=query1(x<<1,l,mid,ql,qr);
    if(qr>mid) ret+=query1(x<<1|1,mid+1,r,ql,qr);
    return ret;
}

inline void merge(int x){
    int A=LX,B=RX,C=MX,D=SUM;
    SUM=D+sum[x];
    if(D==RR-LL+1) LX=D+lx1[x];
    RX=rx1[x];
    if(sum[x]==R[x]-L[x]+1) RX=B+sum[x];
    MX=max(C,max(mx1[x],B+lx1[x]));
    ans=max(ans,MX);
    if(!LL) LL=L[x];
    RR=R[x];
}

inline void query2(int x,int l,int r,int ql,int qr){
    if(ql<=l && r<=qr) {merge(x);return;}
    int mid=l+r>>1;
    pushdown(x);
    if(ql<=mid) query2(x<<1,l,mid,ql,qr);
    if(qr>mid) query2(x<<1|1,mid+1,r,ql,qr);
}

int main(){
    n=rd();m=rd();
    for(register int i=1;i<=n;i++) a[i]=rd();
    build(1,1,n);
//  for(register int i=1;i<=(n<<1);i++)
//      cout<<L[i]<<" "<<R[i]<<" "<<sum[i]<<" "<<endl;
    while(m--){
//      cout<<sum[1]<<endl;
        int op=rd(),ql=rd(),qr=rd();ql++;qr++;
        if(op==0 || op==1 || op==2) update(1,1,n,ql,qr,op); 
        else if(op==3) printf("%d\n",query1(1,1,n,ql,qr));
        else if(op==4) {query2(1,1,n,ql,qr);printf("%d\n",ans);ans=LX=RX=MX=SUM=LL=RR=0;}
    }
    return 0;
}

转载于:https://www.cnblogs.com/sdfzsyq/p/9676938.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值