bzoj 1858: [Scoi2010]序列操作

bzoj 1858: [Scoi2010]序列操作

线段树

题意

给一个01串,设计数据结构,支持5种操作:

  1. 区间置零
  2. 区间置一
  3. 区间翻转,0变1,1变0
  4. 查询区间1的个数
  5. 查询区间内最长的连续1的个数

思路

线段树维护连续子区间。就是复杂一点而已。因为有翻转操作,所以要同时维护0和1的信息。
维护区间0、1的个数,区间最长连续0、1,最长前缀0、1,最长后缀0、1。
最好重载+号,pushup就相当于做加法。

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
int max3(int a, int b, int c) { return std::max(std::max(a, b), c); }
int num[MAXN];
struct Stree
{
    int flip;//翻转
    int num0, num1;//0的个数,1的个数
    int set0, set1;//置0,置1
    int pre0, pre1;//连续前缀0,连续前缀1
    int suf0, suf1;//连续后缀0,连续后缀1
    int ma0, ma1;//最长连续0,最长连续1
    inline void init() { flip=num0=num1=set0=set1=pre0=pre1=suf0=suf1=ma0=ma1=0; }
}stree[MAXN<<2];
void pushup(int l, int r, int rt)
{
    stree[rt].num0=stree[rt<<1].num0+stree[rt<<1|1].num0;
    stree[rt].num1=stree[rt<<1].num1+stree[rt<<1|1].num1;
    stree[rt].ma0=max3(stree[rt<<1].ma0, stree[rt<<1|1].ma0, stree[rt<<1].suf0+stree[rt<<1|1].pre0);
    stree[rt].ma1=max3(stree[rt<<1].ma1, stree[rt<<1|1].ma1, stree[rt<<1].suf1+stree[rt<<1|1].pre1);
    int mid=(l+r)>>1;
    if(stree[rt<<1].pre0==mid-l+1)
        stree[rt].pre0=stree[rt<<1].pre0+stree[rt<<1|1].pre0;
    else stree[rt].pre0=stree[rt<<1].pre0;

    if(stree[rt<<1].pre1==mid-l+1)
        stree[rt].pre1=stree[rt<<1].pre1+stree[rt<<1|1].pre1;
    else stree[rt].pre1=stree[rt<<1].pre1;

    if(stree[rt<<1|1].suf0==r-mid)
        stree[rt].suf0=stree[rt<<1].suf0+stree[rt<<1|1].suf0;
    else stree[rt].suf0=stree[rt<<1|1].suf0;

    if(stree[rt<<1|1].suf1==r-mid)
        stree[rt].suf1=stree[rt<<1].suf1+stree[rt<<1|1].suf1;
    else stree[rt].suf1=stree[rt<<1|1].suf1;
}
void pushdown(int l, int r, int rt)
{
    int mid=(l+r)>>1;
    if(stree[rt].set0)
    {
        stree[rt].set0=0;

        stree[rt<<1].flip=stree[rt<<1].set1=0;stree[rt<<1].set0=1;
        stree[rt<<1].num0=mid-l+1;stree[rt<<1].num1=0;
        stree[rt<<1].pre0=stree[rt<<1].suf0=stree[rt<<1].ma0=mid-l+1;
        stree[rt<<1].pre1=stree[rt<<1].suf1=stree[rt<<1].ma1=0;

        stree[rt<<1|1].flip=stree[rt<<1|1].set1=0;stree[rt<<1|1].set0=1;
        stree[rt<<1|1].num0=r-mid;stree[rt<<1|1].num1=0;
        stree[rt<<1|1].pre0=stree[rt<<1|1].suf0=stree[rt<<1|1].ma0=r-mid;
        stree[rt<<1|1].pre1=stree[rt<<1|1].suf1=stree[rt<<1|1].ma1=0;
    }
    else if(stree[rt].set1)
    {
        stree[rt].set1=0;

        stree[rt<<1].flip=stree[rt<<1].set0=0;stree[rt<<1].set1=1;
        stree[rt<<1].num1=mid-l+1;stree[rt<<1].num0=0;
        stree[rt<<1].pre1=stree[rt<<1].suf1=stree[rt<<1].ma1=mid-l+1;
        stree[rt<<1].pre0=stree[rt<<1].suf0=stree[rt<<1].ma0=0;

        stree[rt<<1|1].flip=stree[rt<<1|1].set0=0;stree[rt<<1|1].set1=1;
        stree[rt<<1|1].num1=r-mid;stree[rt<<1|1].num0=0;
        stree[rt<<1|1].pre1=stree[rt<<1|1].suf1=stree[rt<<1|1].ma1=r-mid;
        stree[rt<<1|1].pre0=stree[rt<<1|1].suf0=stree[rt<<1|1].ma0=0;
    }
    else if(stree[rt].flip)
    {
        stree[rt].flip=0;

        stree[rt<<1].flip^=1;
        if(stree[rt<<1].set0) stree[rt<<1].set1=1, stree[rt<<1].set0=0, stree[rt<<1].flip=0;
        else if(stree[rt<<1].set1) stree[rt<<1].set0=1, stree[rt<<1].set1=0, stree[rt<<1].flip=0;
        swap(stree[rt<<1].ma0, stree[rt<<1].ma1);
        swap(stree[rt<<1].num0, stree[rt<<1].num1);
        swap(stree[rt<<1].pre0, stree[rt<<1].pre1);
        swap(stree[rt<<1].suf0, stree[rt<<1].suf1);

        stree[rt<<1|1].flip^=1;
        if(stree[rt<<1|1].set0) stree[rt<<1|1].set1=1, stree[rt<<1|1].set0=0, stree[rt<<1|1].flip=0;
        else if(stree[rt<<1|1].set1) stree[rt<<1|1].set0=1, stree[rt<<1|1].set1=0, stree[rt<<1|1].flip=0;
        swap(stree[rt<<1|1].ma0, stree[rt<<1|1].ma1);
        swap(stree[rt<<1|1].num0, stree[rt<<1|1].num1);
        swap(stree[rt<<1|1].pre0, stree[rt<<1|1].pre1);
        swap(stree[rt<<1|1].suf0, stree[rt<<1|1].suf1);
    }
}
void build(int l, int r, int rt)
{
    stree[rt].init();
    if(l==r)
    {
        if(num[l]) stree[rt].num1=stree[rt].pre1=stree[rt].suf1=stree[rt].ma1=1;
        else stree[rt].num0=stree[rt].pre0=stree[rt].suf0=stree[rt].ma0=1;
        return;
    }
    int mid=(l+r)>>1;
    build(lson), build(rson);
    pushup(l, r, rt);
}
void update(int L, int R, int k, int l, int r, int rt)
{
    if(L<=l&&r<=R)
    {
        if(k==0)//set0
        {
            if(stree[rt].set0) return;
            else
            {
                stree[rt].set1=stree[rt].flip=0;stree[rt].set0=1;
                stree[rt].num0=stree[rt].pre0=stree[rt].suf0=stree[rt].ma0=r-l+1;
                stree[rt].num1=stree[rt].pre1=stree[rt].suf1=stree[rt].ma1=0;
            }
        }
        else if(k==1)//set1
        {
            if(stree[rt].set1) return;
            else
            {
                stree[rt].set0=stree[rt].flip=0;stree[rt].set1=1;
                stree[rt].num0=stree[rt].pre0=stree[rt].suf0=stree[rt].ma0=0;
                stree[rt].num1=stree[rt].pre1=stree[rt].suf1=stree[rt].ma1=r-l+1;
            }
        }
        else if(k==2)//flip
        {
            if(stree[rt].set0) stree[rt].set0=0, stree[rt].set1=1, stree[rt].flip=0;
            else if(stree[rt].set1) stree[rt].set0=1, stree[rt].set1=0, stree[rt].flip=0;
            else stree[rt].flip^=1;
            swap(stree[rt].ma0, stree[rt].ma1);
            swap(stree[rt].num0, stree[rt].num1);
            swap(stree[rt].pre0, stree[rt].pre1);
            swap(stree[rt].suf0, stree[rt].suf1);
        }
        return;
    }
    pushdown(l, r, rt);
    int mid=(l+r)>>1;
    if(L<=mid) update(L, R, k, lson);
    if(R>mid) update(L, R, k, rson);
    pushup(l, r, rt);
}
int query1(int L, int R, int l, int r, int rt)
{
    if(L<=l&&r<=R) return stree[rt].num1;
    pushdown(l, r, rt);
    int mid=(l+r)>>1;
    int sum=0;
    if(L<=mid) sum+=query1(L, R, lson);
    if(mid<R) sum+=query1(L, R, rson);
    return sum;
}
Stree query2(int L, int R, int l, int r, int rt)
{
    if(L<=l&&r<=R) return stree[rt];
    pushdown(l, r, rt);
    int mid=(l+r)>>1;
    Stree ll, rr;ll.init(), rr.init();
    if(L<=mid) ll=query2(L, R, lson);
    if(mid<R) rr=query2(L, R, rson);
    Stree res;res.init();
    res.ma1=max3(ll.ma1, rr.ma1, ll.suf1+rr.pre1);
    if(ll.pre1==mid-l+1)
        res.pre1=ll.pre1+rr.pre1;
    else res.pre1=ll.pre1;

    if(rr.suf1==r-mid)
        res.suf1=ll.suf1+rr.suf1;
    else res.suf1=rr.suf1;


    return res;
}
int main()
{
    int n, m;scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++) scanf("%d", &num[i]);
    build(1, n, 1);
    for(int i=1;i<=m;i++)
    {
        int op, x, y;scanf("%d%d%d", &op, &x, &y);x++, y++;
        if(op==0)
            update(x, y, 0, 1, n, 1);
        else if(op==1)
            update(x, y, 1, 1, n, 1);
        else if(op==2)
            update(x, y, 2, 1, n, 1);
        else if(op==3)
            printf("%d\n", query1(x, y, 1, n, 1));
        else if(op==4)
            printf("%d\n", query2(x, y, 1, n, 1).ma1);
    }
    //system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值