BZOJ1858 [Scoi2010]序列操作

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 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

题解

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

#include <cstdio>
#include <iostream>
#include <cmath>
#include <stack>
#include <algorithm>
#include <cstring>
#include <climits>
#define MAXN 100000+10
using 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值