BZOJ1858: [Scoi2010]序列操作

【传送门:BZOJ1858


简要题意:

  给出一个长度为n的01序列,有五种操作,m个操作:

  0 x y将第x个数到第y个数都变成0

  1 x y将第x个数到第y个数都变成1

  2 x y将第x个数到第y个数的所有数取反(即0变为1,1变为0)

  3 x y求出第x个数到第y个数有多少个1

  4 x y求出第x个数到第y个数最多有多少个连续的1


题解:

  线段树麻烦题

  对于一段区间,我们维护这些东西:

  c表示有多少个1,c0表示最多有多少个连续的0,c1表示最多有多少个连续的1

  lc0表示从左端点开始向右有多少个连续的0,lc1表示从左端点开始向右有多少个连续的1

  rc0表示从右端点开始向左有多少个连续的0,rc1表示从右端点开始向左有多少个连续的1

  然后对于标记,lazy01表示当前区间的子区间变0或变1或不变,fan表示当前区间是否需要取反

  因为不能知道先后顺序,所以我们使得这两个标记在一个区间内不同时存在就好了

  假如当前区间原本就有取反标记,如果我要使得这个区间变为0或1,那么就要把取反标记去掉(因为这个时候取反没有用的,反正也会变成0或1)

  假如当前区间原本就有01标记,如果我要使得这个区间取反,那么就要把取反标记去掉,然后把01标记变成另一个01标记(也就是原本要变0的就变1,原本要变1的就变0,就是相当于取反了)

  然后其他的无脑做就好了,第四个操作略微有些麻烦


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
    int l,r,lc,rc,c,c0,c1;
    int lc0,lc1,rc0,rc1;
    int lazy01,fan;
}tr[210000];int trlen;
void bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].c=tr[now].c0=tr[now].c1=tr[now].lc0=tr[now].lc1=tr[now].rc0=tr[now].rc1=0;
    tr[now].lazy01=-1;tr[now].fan=0;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
void follow(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    
    tr[now].c=tr[lc].c+tr[rc].c;
    
    tr[now].c0=max(tr[lc].rc0+tr[rc].lc0,max(tr[lc].c0,tr[rc].c0));
    tr[now].c1=max(tr[lc].rc1+tr[rc].lc1,max(tr[lc].c1,tr[rc].c1));
    
    if(tr[lc].lc0==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc0==(tr[rc].r-tr[rc].l+1)) tr[now].lc0=tr[now].rc0=tr[now].r-tr[now].l+1;
    else if(tr[lc].lc0==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc0!=(tr[rc].r-tr[rc].l+1)) tr[now].lc0=tr[lc].lc0+tr[rc].lc0,tr[now].rc0=tr[rc].rc0;
    else if(tr[lc].lc0!=(tr[lc].r-tr[lc].l+1)&&tr[rc].rc0==(tr[rc].r-tr[rc].l+1)) tr[now].rc0=tr[lc].rc0+tr[rc].rc0,tr[now].lc0=tr[lc].lc0;
    else tr[now].lc0=tr[lc].lc0,tr[now].rc0=tr[rc].rc0;
    
    if(tr[lc].lc1==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc1==(tr[rc].r-tr[rc].l+1)) tr[now].lc1=tr[now].rc1=tr[now].r-tr[now].l+1;
    else if(tr[lc].lc1==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc1!=(tr[rc].r-tr[rc].l+1)) tr[now].lc1=tr[lc].lc1+tr[rc].lc1,tr[now].rc1=tr[rc].rc1;
    else if(tr[lc].lc1!=(tr[lc].r-tr[lc].l+1)&&tr[rc].rc1==(tr[rc].r-tr[rc].l+1)) tr[now].rc1=tr[lc].rc1+tr[rc].rc1,tr[now].lc1=tr[lc].lc1;
    else tr[now].lc1=tr[lc].lc1,tr[now].rc1=tr[rc].rc1;
}
void update01(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    if(lc!=-1)
    {
        if(tr[now].lazy01==0)
        {
            tr[lc].c=tr[lc].c1=0;
            tr[lc].c0=tr[lc].r-tr[lc].l+1;
            tr[lc].lc0=tr[lc].rc0=tr[lc].r-tr[lc].l+1;
            tr[lc].lc1=tr[lc].rc1=0;
            tr[lc].lazy01=0;
        }
        else
        {
            tr[lc].c=tr[lc].c1=tr[lc].r-tr[lc].l+1;
            tr[lc].c0=0;
            tr[lc].lc0=tr[lc].rc0=0;
            tr[lc].lc1=tr[lc].rc1=tr[lc].r-tr[lc].l+1;
            tr[lc].lazy01=1;
        }
        if(tr[lc].fan==1) tr[lc].fan=0;
    }
    if(rc!=-1)
    {
        if(tr[now].lazy01==0)
        {
            tr[rc].c=tr[rc].c1=0;
            tr[rc].c0=tr[rc].r-tr[rc].l+1;
            tr[rc].lc0=tr[rc].rc0=tr[rc].r-tr[rc].l+1;
            tr[rc].lc1=tr[rc].rc1=0;
            tr[rc].lazy01=0;
        }
        else
        {
            tr[rc].c=tr[rc].c1=tr[rc].r-tr[rc].l+1;
            tr[rc].c0=0;
            tr[rc].lc0=tr[rc].rc0=0;
            tr[rc].lc1=tr[rc].rc1=tr[rc].r-tr[rc].l+1;
            tr[rc].lazy01=1;
        }
        if(tr[rc].fan==1) tr[rc].fan=0;
    }
    tr[now].lazy01=-1;
}
void updatef(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    if(lc!=-1)
    {
        tr[lc].c=(tr[lc].r-tr[lc].l+1)-tr[lc].c;
        swap(tr[lc].c0,tr[lc].c1);
        swap(tr[lc].lc0,tr[lc].lc1);
        swap(tr[lc].rc0,tr[lc].rc1);
        tr[lc].fan^=1;
        if(tr[lc].fan==1&&tr[lc].lazy01!=-1)
        {
            tr[lc].lazy01^=1;
            tr[lc].fan=0;
        }
    }
    if(rc!=-1)
    {
        tr[rc].c=(tr[rc].r-tr[rc].l+1)-tr[rc].c;
        swap(tr[rc].c0,tr[rc].c1);
        swap(tr[rc].lc0,tr[rc].lc1);
        swap(tr[rc].rc0,tr[rc].rc1);
        tr[rc].fan^=1;
        if(tr[rc].fan==1&&tr[rc].lazy01!=-1)
        {
            tr[rc].lazy01^=1;
            tr[rc].fan=0;
        }
    }
    tr[now].fan=0;
}
void change(int now,int l,int r,int c)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        if(c==0)
        {
            tr[now].c=tr[now].c1=0;
            tr[now].c0=r-l+1;
            tr[now].lc0=tr[now].rc0=r-l+1;
            tr[now].lc1=tr[now].rc1=0;
            tr[now].lazy01=0;
        }
        else
        {
            tr[now].c=tr[now].c1=r-l+1;
            tr[now].c0=0;
            tr[now].lc0=tr[now].rc0=0;
            tr[now].lc1=tr[now].rc1=r-l+1;
            tr[now].lazy01=1;
        }
        if(tr[now].fan==1) tr[now].fan=0;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy01!=-1) update01(now);
    if(tr[now].fan==1) updatef(now);
    if(r<=mid) change(lc,l,r,c);
    else if(l>mid) change(rc,l,r,c);
    else change(lc,l,mid,c),change(rc,mid+1,r,c);
    follow(now);
}
void qufan(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        tr[now].c=(r-l+1)-tr[now].c;
        swap(tr[now].c0,tr[now].c1);
        swap(tr[now].lc0,tr[now].lc1);
        swap(tr[now].rc0,tr[now].rc1);
        tr[now].fan^=1;
        if(tr[now].fan==1&&tr[now].lazy01!=-1)
        {
            tr[now].lazy01^=1;
            tr[now].fan=0;
        }
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy01!=-1) update01(now);
    if(tr[now].fan==1) updatef(now);
    if(r<=mid) qufan(lc,l,r);
    else if(l>mid) qufan(rc,l,r);
    else qufan(lc,l,mid),qufan(rc,mid+1,r);
    follow(now);
}
int findc(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r) return tr[now].c;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy01!=-1) update01(now);
    if(tr[now].fan==true) updatef(now);
    if(r<=mid) return findc(lc,l,r);
    else if(l>mid) return findc(rc,l,r);
    else return findc(lc,l,mid)+findc(rc,mid+1,r);
}
int tot,p[110000];
void findd(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        p[++tot]=now;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy01!=-1) update01(now);
    if(tr[now].fan==true) updatef(now);
    if(r<=mid) findd(lc,l,r);
    else if(l>mid) findd(rc,l,r);
    else findd(lc,l,mid),findd(rc,mid+1,r);
}
int a[110000];
int main()
{
    freopen("operation.in","r",stdin);
    freopen("operation.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    trlen=0;bt(1,n);
    for(int i=1;i<=n;i++)
    {
        int c;
        scanf("%d",&c);
        change(1,i,i,c);
    }
    for(int i=1;i<=m;i++)
    {
        int opt,x,y;
        scanf("%d%d%d",&opt,&x,&y);x++;y++;
        if(opt==0) change(1,x,y,0);
        if(opt==1) change(1,x,y,1);
        if(opt==2) qufan(1,x,y);
        if(opt==3) printf("%d\n",findc(1,x,y));
        if(opt==4)
        {
            tot=0;
            findd(1,x,y);
            int ans=0,t=0;
            for(int i=1;i<=tot;i++)
            {
                ans=max(ans,tr[p[i]].c1);
                if(tr[p[i]].c1==(tr[p[i]].r-tr[p[i]].l+1)) t+=tr[p[i]].c1;
                else
                {
                    ans=max(ans,t+tr[p[i]].lc1);
                    t=tr[p[i]].rc1;
                }
                ans=max(ans,t);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

posted @ 2018-04-11 07:57  Star_Feel  阅读(201)  评论(0编辑  收藏  举报