[BZOJ 1858][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

Solution


啊为什么调了那么长时间…
后来发现是push_down操作给子节点标lazy的时候忘记把它们的rev标记去掉了 泪

线段记录区间里1和0的个数、最长连续的1和0的个数、左端连续的1和0的个数、右端连续的1和0的个数,然后记录一个lazy标记和rev标记(取反)。
取反操作的时候遇到lazy标记可以直接对lazy取反,标记lazy的时候要记得把rev去掉
那个最长连续1的询问函数直接返回了一个结构体,合并操作和线段树的更新差不多,具体实现看代码

感觉我没有办法写出优美的代码,不知道为什么代码长度这么长= =

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<assert.h>
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define mid(a,b) ((a+b)>>1)
#define MAXN 100005
using namespace std;
int n,m;
int x[MAXN],ans;
struct Node{
    int l,r,siz;
    int num1,lnum1,rnum1,maxnum1;
    int num0,lnum0,rnum0,maxnum0;
    int lazy,rev;
}t[MAXN*4];
Node operator + (const Node& a,const Node& b)
{
    Node ans;

    ans.lnum0=a.lnum0;
    if(a.lnum0==a.siz)
    ans.lnum0=a.siz+b.lnum0;
    ans.lnum1=a.lnum1;
    if(a.lnum1==a.siz)
    ans.lnum1=a.siz+b.lnum1;

    ans.rnum0=b.rnum0;
    if(b.rnum0==b.siz)
    ans.rnum0=b.siz+a.rnum0;
    ans.rnum1=b.rnum1;
    if(b.rnum1==b.siz)
    ans.rnum1=b.siz+a.rnum1;

    ans.num0=a.num0+b.num0;
    ans.num1=a.num1+b.num1;

    ans.maxnum0=Max(a.maxnum0,b.maxnum0);
    ans.maxnum0=Max(ans.maxnum0,a.rnum0+b.lnum0);

    ans.maxnum1=Max(a.maxnum1,b.maxnum1);
    ans.maxnum1=Max(ans.maxnum1,a.rnum1+b.lnum1);
    return ans;
}
void _exchange(int idx)
{
    swap(t[idx].lnum0,t[idx].lnum1);
    swap(t[idx].rnum0,t[idx].rnum1);
    swap(t[idx].num0,t[idx].num1);
    swap(t[idx].maxnum0,t[idx].maxnum1);
}
void push_down(int idx)
{
    if(t[idx].l==t[idx].r)return;
    if(t[idx].lazy!=-1)
    {
        int f=t[idx].lazy;
        t[idx*2].lazy=t[idx*2+1].lazy=t[idx].lazy;
        t[idx*2].rev=t[idx*2+1].rev=0;
        t[idx].lazy=-1;
        t[idx*2].lnum0=t[idx*2].rnum0=t[idx*2].num0=t[idx*2].maxnum0=(f==0)*t[idx*2].siz;
        t[idx*2].lnum1=t[idx*2].rnum1=t[idx*2].num1=t[idx*2].maxnum1=(f==1)*t[idx*2].siz;
        t[idx*2+1].lnum0=t[idx*2+1].rnum0=t[idx*2+1].num0=t[idx*2+1].maxnum0=(f==0)*t[idx*2+1].siz;
        t[idx*2+1].lnum1=t[idx*2+1].rnum1=t[idx*2+1].num1=t[idx*2+1].maxnum1=(f==1)*t[idx*2+1].siz;
    }
    if(t[idx].rev)
    {
        t[idx].rev=0;
        t[idx*2].rev^=1;
        t[idx*2+1].rev^=1;
        _exchange(idx*2);
        _exchange(idx*2+1);
    }
}
void _update(int idx)
{
    t[idx].lnum0=t[idx*2].lnum0;
    if(t[idx*2].lnum0==t[idx*2].siz)
    t[idx].lnum0=t[idx*2].siz+t[idx*2+1].lnum0;
    t[idx].lnum1=t[idx*2].lnum1;
    if(t[idx*2].lnum1==t[idx*2].siz)
    t[idx].lnum1=t[idx*2].siz+t[idx*2+1].lnum1;

    t[idx].rnum0=t[idx*2+1].rnum0;
    if(t[idx*2+1].rnum0==t[idx*2+1].siz)
    t[idx].rnum0=t[idx*2+1].siz+t[idx*2].rnum0;
    t[idx].rnum1=t[idx*2+1].rnum1;
    if(t[idx*2+1].rnum1==t[idx*2+1].siz)
    t[idx].rnum1=t[idx*2+1].siz+t[idx*2].rnum1;

    t[idx].num0=t[idx*2].num0+t[idx*2+1].num0;
    t[idx].num1=t[idx*2].num1+t[idx*2+1].num1;

    t[idx].maxnum0=Max(t[idx*2].maxnum0,t[idx*2+1].maxnum0);
    t[idx].maxnum0=Max(t[idx].maxnum0,t[idx*2].rnum0+t[idx*2+1].lnum0);

    t[idx].maxnum1=Max(t[idx*2].maxnum1,t[idx*2+1].maxnum1);
    t[idx].maxnum1=Max(t[idx].maxnum1,t[idx*2].rnum1+t[idx*2+1].lnum1);
}
void _build(int idx,int a,int b)
{
    t[idx].siz=b-a+1;
    t[idx].l=a;t[idx].r=b;
    t[idx].lazy=-1;
    t[idx].rev=0;
    if(a==b)
    {
        if(x[a])
        {
            t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=0;
            t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=1;
        }
        else 
        {
            t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=1;
            t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=0;
        }
        return;
    }
    int m=mid(a,b);
    _build(idx*2,a,m);
    _build(idx*2+1,m+1,b);
    _update(idx);
}
void _turn(int idx,int a,int b,int f)
{
    push_down(idx);
    if(t[idx].l==t[idx].r)
    {
        t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=(f==0);
        t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=(f==1);
        return;
    }
    if(a<=t[idx].l&&b>=t[idx].r)
    {
        t[idx].lnum0=t[idx].rnum0=t[idx].num0=t[idx].maxnum0=(f==0)*t[idx].siz;
        t[idx].lnum1=t[idx].rnum1=t[idx].num1=t[idx].maxnum1=(f==1)*t[idx].siz;
        if(t[idx].rev)
        t[idx].rev=0;
        t[idx].lazy=f;
        return;
    }

    int m=mid(t[idx].l,t[idx].r);
    if(b<=m)_turn(idx*2,a,b,f);
    else if(a>m)_turn(idx*2+1,a,b,f);
    else
    {
        _turn(idx*2,a,b,f);
        _turn(idx*2+1,a,b,f);
    }
    _update(idx);
}
void _reverse(int idx,int a,int b)
{
    push_down(idx);
    if(t[idx].l==t[idx].r)
    {
        _exchange(idx);
        return;
    }
    if(a<=t[idx].l&&b>=t[idx].r)
    {
        if(t[idx].lazy!=-1)
        {
            t[idx].lazy^=1;
            _exchange(idx);
            return;
        }
        t[idx].rev^=1;
        _exchange(idx);
        return;
    }
    int m=mid(t[idx].l,t[idx].r);
    if(b<=m)_reverse(idx*2,a,b);
    else if(a>m)_reverse(idx*2+1,a,b);
    else
    {
        _reverse(idx*2,a,b);
        _reverse(idx*2+1,a,b);
    }
    _update(idx);
}
void _count(int idx,int a,int b)
{
    push_down(idx);
    if(t[idx].l==t[idx].r)
    {
        ans+=t[idx].num1;
        return;
    }

    if(a<=t[idx].l&&b>=t[idx].r)
    {
        ans+=t[idx].num1;
        return;
    }

    int m=mid(t[idx].l,t[idx].r);
    if(b<=m)_count(idx*2,a,b);
    else if(a>m)_count(idx*2+1,a,b);
    else
    {
        _count(idx*2,a,b);
        _count(idx*2+1,a,b);
    }
}
Node _query(int idx,int a,int b)
{
    push_down(idx);
    if(a==t[idx].l&&b==t[idx].r)
    {
        return t[idx];
    }

    int m=mid(t[idx].l,t[idx].r);
    if(a<=m&&b>m)
    {
        return _query(idx*2,a,m)+_query(idx*2+1,m+1,b);
    }
    if(a>m)
    {
        return _query(idx*2+1,a,b);
    }
    if(b<=m)
    {
        return _query(idx*2,a,b);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    scanf("%d",&x[i]);
    _build(1,0,n-1);
    for(int i=1;i<=m;i++)
    {
        int opt,a,b;
        scanf("%d%d%d",&opt,&a,&b);
        switch(opt)
        {
            case 0:
            _turn(1,a,b,0);break;
            case 1:
            _turn(1,a,b,1);break;   
            case 2:
            _reverse(1,a,b);break;
            case 3:
            ans=0;_count(1,a,b);printf("%d\n",ans);break;
            case 4:
            Node res=_query(1,a,b);
            printf("%d\n",res.maxnum1);break;

        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章