题解 P2572 【[SCOI2010]序列操作】

搬迁洛谷博客至此

搬迁洛谷博客至此

搬迁洛谷博客至此

重要的事情说三遍

这道题太坑了,我做了加起来一天才AC,找错找过来找过去,发现是pushup()错了(泪奔,最开始我信誓旦旦的说pushup()没错,结果就pushup()最多)

这道题难度中规中矩,就是细节处理非常多,错一点就要找很久。

怎么做?

首先看题,有2种修改(3个),2个询问,最开始我开了两个lazy标记,但其实不用,那样反而更麻烦。开一个lazy标记就够了。

每次修改,就分类讨论:当opt == 0 || opt == 1时直接修改,下传标记;当opt==2时,就要分成3大类,当前区间sign=-1,sign=2,sign=1||sign=0,这里较麻烦,可直接看我代码;
downdate()和上面差不多;

然后一定要注意pushup(),这个函数其实很短,但很重要,处理一定要恰当。

查询连续的1怎么办?

这个做法比较巧妙,可以用一个pre,记录左区间的maxr,向上更新,然后查找右区间的maxl,然后与maxx比较(因为查询的区间可能不能被一个线段树中的区间包含完,所以有可能被分为两段查询)。

上代码(大家不懂的地方,看了代码应该就懂了,代码很容易懂,耐心阅读_):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls id<<1
#define rs id<<1|1
using namespace std;
const int N=100000+10;
int n,m,a[N],ans=0,pre;
struct node
{
    int left,right,sign,sum,maxx,maxl,maxr,maxl0,maxr0,maxx0;
}tree[N*4];
void pushup(int id)//可恶的函数
{
    tree[id].sum=tree[ls].sum+tree[rs].sum;
    tree[id].maxl=tree[ls].maxl;tree[id].maxl0=tree[ls].maxl0;
    if(tree[id].maxl==tree[ls].right-tree[ls].left+1)tree[id].maxl+=tree[rs].maxl;
    if(tree[id].maxl0==tree[ls].right-tree[ls].left+1)tree[id].maxl0+=tree[rs].maxl0;
    tree[id].maxr=tree[rs].maxr;tree[id].maxr0=tree[rs].maxr0;
    if(tree[id].maxr==tree[rs].right-tree[rs].left+1)tree[id].maxr+=tree[ls].maxr;
    if(tree[id].maxr0==tree[rs].right-tree[rs].left+1)tree[id].maxr0+=tree[ls].maxr0;
    tree[id].maxx=max(tree[ls].maxx,max(tree[rs].maxx,tree[ls].maxr+tree[rs].maxl));
    tree[id].maxx0=max(tree[ls].maxx0,max(tree[rs].maxx0,tree[ls].maxr0+tree[rs].maxl0));
}
void built(int id,int l,int r)
{
    tree[id].left=l,tree[id].right=r,tree[id].sign=-1;
    if(l==r)
    {
        tree[id].maxl=tree[id].maxr=tree[id].maxx=tree[id].sum=a[l];
        tree[id].maxl0=tree[id].maxr0=tree[id].maxx0=(a[l]^1);
        return;
    }
    int mid=(l+r)>>1;
    built(ls,l,mid),built(rs,mid+1,r);pushup(id);
}
void change(int id)
{
    swap(tree[id].maxl,tree[id].maxl0);swap(tree[id].maxr,tree[id].maxr0);swap(tree[id].maxx,tree[id].maxx0);
    tree[id].sum=tree[id].right-tree[id].left+1-tree[id].sum;
}
void downdate(int id)
{
    if(tree[id].sign<=1&&tree[id].sign>=0)
    {
        int tmp;
        tmp=(tree[ls].right-tree[ls].left+1);
        tree[ls].sign=tree[id].sign;
        tree[ls].maxl=tree[ls].maxr=tree[ls].maxx=tree[ls].sum=tmp*tree[id].sign;
        tree[ls].maxl0=tree[ls].maxr0=tree[ls].maxx0=tmp*(tree[id].sign^1);
        tmp=(tree[rs].right-tree[rs].left+1);
        tree[rs].sign=tree[id].sign;
        tree[rs].maxl=tree[rs].maxr=tree[rs].maxx=tree[rs].sum=tmp*tree[id].sign;
        tree[rs].maxl0=tree[rs].maxr0=tree[rs].maxx0=tmp*(tree[id].sign^1);
    }
    else if(tree[id].sign==2)
    {
        if(tree[ls].sign<=1&&tree[ls].sign>=0)
        {
            int tmp=(tree[ls].right-tree[ls].left+1);
            tree[ls].maxl=tree[ls].maxr=tree[ls].maxx=tree[ls].sum=tmp*(tree[ls].sign^1);
            tree[ls].maxl0=tree[ls].maxr0=tree[ls].maxx0=tmp*tree[ls].sign;
            tree[ls].sign^=1;
        }
        else if(tree[ls].sign==-1)
        {
            change(ls);tree[ls].sign=2;
        }
        else if(tree[ls].sign==2)
        {
            change(ls);tree[ls].sign=-1;
        }
        if(tree[rs].sign<=1&&tree[rs].sign>=0)
        {
            int tmp=(tree[rs].right-tree[rs].left+1);
            tree[rs].maxl=tree[rs].maxr=tree[rs].maxx=tree[rs].sum=tmp*(tree[rs].sign^1);
            tree[rs].maxl0=tree[rs].maxr0=tree[rs].maxx0=tmp*tree[rs].sign;
            tree[rs].sign^=1;
        }
        else if(tree[rs].sign==-1)
        {
            change(rs);tree[rs].sign=2;
        }
        else if(tree[rs].sign==2)
        {
            change(rs);tree[rs].sign=-1;
        }
    }tree[id].sign=-1;
}
void update(int id,int l,int r,int opt)
{
    if(tree[id].left>r||tree[id].right<l)return;
    if(tree[id].left>=l&&tree[id].right<=r)
    {
        if(opt==0||opt==1)
        {
            int tmp=(tree[id].right-tree[id].left+1);tree[id].sign=opt;
            tree[id].maxl=tree[id].maxr=tree[id].maxx=tree[id].sum=tmp*tree[id].sign;
            tree[id].maxl0=tree[id].maxr0=tree[id].maxx0=tmp*(tree[id].sign^1);
        }
        else if(opt==2)
        {
            if(tree[id].sign==2)
            {
                change(id);tree[id].sign=-1;
            }
            else if(tree[id].sign<=1&&tree[id].sign>=0)
            {
                int tmp=(tree[id].right-tree[id].left+1);tree[id].sign^=1;
                tree[id].maxl=tree[id].maxr=tree[id].maxx=tree[id].sum=tmp*tree[id].sign;
                tree[id].maxl0=tree[id].maxr0=tree[id].maxx0=tmp*(tree[id].sign^1);
            }
            else if(tree[id].sign==-1)
            {
                change(id);tree[id].sign=2;
            }
        }
        return;
    }
    if(tree[id].sign>=0)downdate(id);
    update(ls,l,r,opt);update(rs,l,r,opt);pushup(id);
}
int querysum(int id,int l,int r)
{
    if(tree[id].left>r||tree[id].right<l)return 0;
    if(tree[id].left>=l&&tree[id].right<=r)return tree[id].sum;
    if(tree[id].sign>=0)downdate(id);
    int tmp=querysum(ls,l,r)+querysum(rs,l,r);
    return tmp;
}
void querymaxx(int id,int l,int r)
{
    if(tree[id].left>r||tree[id].right<l)return;
    if(tree[id].left>=l&&tree[id].right<=r)
    {
        ans=max(ans,max(tree[id].maxx,pre+tree[id].maxl));
        if(tree[id].sum==tree[id].right-tree[id].left+1) pre+=tree[id].sum;
        else pre=tree[id].maxr;//巧妙地pre
        return;
    }
    if(tree[id].sign>=0)downdate(id);
    querymaxx(ls,l,r);querymaxx(rs,l,r);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    built(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int x,y,opt;
        scanf("%d%d%d",&opt,&x,&y);x++,y++;
        if(opt<=2)update(1,x,y,opt);
        if(opt==3)printf("%d\n",querysum(1,x,y));
        if(opt==4)ans=0,pre=0,querymaxx(1,x,y),printf("%d\n",ans);
    }
}
发布了11 篇原创文章 · 获赞 3 · 访问量 770

猜你喜欢

转载自blog.csdn.net/steve95/article/details/104215508
今日推荐