[BZOJ1858/Luogu2572][SCOI2010]序列操作

题目链接:

BZOJ1858

Luogu2572

为什么我的代码这么长啊。。

这一看就是个线段树裸题,难点在于第\(4\)个操作。

我们需要在线段树上维护\(6\)个值:

Lm0/1:紧靠左的最长一段\(0/1\)的长度

Rm0/1:紧靠右的最长一段\(0/1\)的长度

Tm0/1:整段中的最长一段\(0/1\)的长度

最后注意修改和翻转操作的优先级:修改的优先级最高(显然)。

然后Debug就好了。

代码:

#include <cstdio>
#include <algorithm>

struct Segment_Tree
{
    struct Node{int Cnt,Tag,Rev,Lm0,Lm1,Rm0,Rm1,Tm0,Tm1;}a[400005];
    //Cnt 1的个数
    //Tag -1/0/1:无修改/覆盖为0/覆盖为1
    //Rev 0/1 是否翻转
    //Lm0/Lm1/Rm0/Rm1/Tm0/Tm1 如上所述

    inline void Pushdown(Node &p,Node &ls,Node &rs,const int ll,const int rl)
    //将p向ls和rs传播标记
    {
        if(~p.Tag)
        //优先考虑修改
        {
            ls.Lm0=ls.Rm0=ls.Tm0=(p.Tag^1)*ll,ls.Lm1=ls.Rm1=ls.Tm1=p.Tag*ll;
            rs.Lm0=rs.Rm0=rs.Tm0=(p.Tag^1)*rl,rs.Lm1=rs.Rm1=rs.Tm1=p.Tag*rl;
            ls.Cnt=p.Tag*ll,rs.Cnt=p.Tag*rl,ls.Tag=rs.Tag=p.Tag,p.Tag=-1,p.Rev=0;
            //修改后不考虑翻转,清空标记
        }
        if(p.Rev)
        {
            if(~ls.Tag)ls.Tag^=1;if(~rs.Tag)rs.Tag^=1;
            ls.Rev^=1,rs.Rev^=1,ls.Cnt=ll-ls.Cnt,rs.Cnt=rl-rs.Cnt,p.Rev=0;
            std::swap(ls.Lm0,ls.Lm1),std::swap(rs.Lm0,rs.Lm1);
            std::swap(ls.Rm0,ls.Rm1),std::swap(rs.Rm0,rs.Rm1);
            std::swap(ls.Tm0,ls.Tm1),std::swap(rs.Tm0,rs.Tm1);
            //翻转操作,也就是0/1的信息互换
        }
    }

    inline Node Pushup(const Node &a,const Node &b,const int al,const int bl)
    //合并a和b,al为a的长度,bl同理
    {
        Node Res;
        Res.Cnt=a.Cnt+b.Cnt,Res.Tag=-1,Res.Rev=0;
        Res.Lm0=!a.Cnt?al+b.Lm0:a.Lm0;
        Res.Lm1=a.Cnt==al?al+b.Lm1:a.Lm1;
        Res.Rm0=!b.Cnt?bl+a.Rm0:b.Rm0;
        Res.Rm1=b.Cnt==bl?bl+a.Rm1:b.Rm1;
        Res.Tm0=std::max(std::max(a.Tm0,b.Tm0),a.Rm0+b.Lm0);
        Res.Tm1=std::max(std::max(a.Tm1,b.Tm1),a.Rm1+b.Lm1);
        return Res;
    }

    void Build(const int p,const int l,const int r)
    {
        if(a[p].Tag=-1,l==r)
        {
            scanf("%d",&a[p].Cnt);
            if(a[p].Cnt)a[p].Lm1=a[p].Rm1=a[p].Tm1=1;
            else a[p].Lm0=a[p].Rm0=a[p].Tm0=1;
            return;
        }
        const int Mid=(l+r)>>1;
        Build(p<<1,l,Mid),Build(p<<1|1,Mid+1,r);
        a[p]=Pushup(a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
    }

    void Cover(const int p,const int l,const int r,const int tl,const int tr,const int v)
    //覆盖操作
    {
        if(tl<=l&&r<=tr)
        {
            a[p].Cnt=v*(r-l+1),a[p].Tag=v;
            a[p].Lm0=a[p].Rm0=a[p].Tm0=(v^1)*(r-l+1);
            a[p].Lm1=a[p].Rm1=a[p].Tm1=v*(r-l+1);
            return;
        }
        const int Mid=(l+r)>>1;
        Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
        if(tl<=Mid)Cover(p<<1,l,Mid,tl,tr,v);
        if(tr>Mid)Cover(p<<1|1,Mid+1,r,tl,tr,v);
        a[p]=Pushup(a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
    }

    void Reverse(const int p,const int l,const int r,const int tl,const int tr)
    //翻转操作
    {
        if(tl<=l&&r<=tr)
        {
            if(~a[p].Tag)a[p].Tag^=1;
            //注意优先级
            a[p].Cnt=r-l+1-a[p].Cnt,a[p].Rev^=1;
            std::swap(a[p].Lm0,a[p].Lm1);
            std::swap(a[p].Rm0,a[p].Rm1);
            std::swap(a[p].Tm0,a[p].Tm1);
            return;
        }
        const int Mid=(l+r)>>1;
        Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
        if(tl<=Mid)Reverse(p<<1,l,Mid,tl,tr);
        if(tr>Mid)Reverse(p<<1|1,Mid+1,r,tl,tr);
        a[p]=Pushup(a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
    }

    int Query_Cnt(const int p,const int l,const int r,const int tl,const int tr)
    //查询1的个数
    {
        if(tl<=l&&r<=tr)return a[p].Cnt;
        int Mid=(l+r)>>1,Res=0;
        Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
        if(tl<=Mid)Res=Query_Cnt(p<<1,l,Mid,tl,tr);
        if(tr>Mid)Res+=Query_Cnt(p<<1|1,Mid+1,r,tl,tr);
        return Res;
    }

    Node Query_Con(const int p,const int l,const int r,const int tl,const int tr)
    //查询连续1的长度
    {
        if(tl<=l&&r<=tr)return a[p];
        const int Mid=(l+r)>>1;
        Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
        if(tr<=Mid)return Query_Con(p<<1,l,Mid,tl,tr);
        if(tl>Mid)return Query_Con(p<<1|1,Mid+1,r,tl,tr);
        return Pushup(Query_Con(p<<1,l,Mid,tl,tr),Query_Con(p<<1|1,Mid+1,r,tl,tr),Mid-l+1,r-Mid);
    }
}Sequence;

int main()
{
    int n,m;scanf("%d%d",&n,&m),Sequence.Build(1,1,n);
    for(int op,l,r;m--;)
        if(scanf("%d%d%d",&op,&l,&r),++l,++r,op<=1)Sequence.Cover(1,1,n,l,r,op);
        else if(op==2)Sequence.Reverse(1,1,n,l,r);
        else if(op==3)printf("%d\n",Sequence.Query_Cnt(1,1,n,l,r));
        else printf("%d\n",Sequence.Query_Con(1,1,n,l,r).Tm1);
    return 0;
}
posted @ 2019-02-15 15:01  LanrTabe  阅读(164)  评论(0编辑  收藏  举报