bzoj1858[Scoi2010]序列操作

Posted narh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1858[Scoi2010]序列操作相关的知识,希望对你有一定的参考价值。

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1858

十分普通的线段树。调了好久……

记录一下0的信息,在reverse的时候比较方便。

1.把修改和pushdown里要用到的东西都写在一个函数里比较方便。别忘了改标记。

  一开始没有把改标记写在那个函数里,结果忘了在pushdown的时候下传rev的标记。

2.修改操作很简单。可以把标记规定成rev和b不同时存在、b[0]和b[1]不同时存在,就很好了。

3.三目运算符要整个括起来。

4.rev标记是^=1。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+5;
int n,m,tot=1,L,R;
bool c[N];
struct Node{
    int ls,rs,cd;
    bool b[2],rev;
    int l[2],r[2],len[2],sum;
}a[N<<1];
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>9||ch<0)ch=getchar();
    while(ch<=9&&ch>=0)(ret*=10)+=ch-0,ch=getchar();
    return ret;
}
void pushup(int cr)
{
    int ls=a[cr].ls,rs=a[cr].rs;
    a[cr].sum=a[ls].sum+a[rs].sum;
    for(int d=0;d<=1;d++)
    {
        a[cr].l[d]=a[ls].l[d]+(a[ls].l[d]==a[ls].cd?a[rs].l[d]:0);//括起来 
        a[cr].r[d]=a[rs].r[d]+(a[rs].r[d]==a[rs].cd?a[ls].r[d]:0);
        a[cr].len[d]=max(max(a[ls].len[d],a[rs].len[d]),a[ls].r[d]+a[rs].l[d]);
    }
}
void build(int l,int r,int cr)
{
    a[cr].cd=r-l+1;
    if(l==r){
        a[cr].l[c[l]]=a[cr].r[c[l]]=a[cr].len[c[l]]=1;
        a[cr].sum=c[l];return;
    }
    int mid=((l+r)>>1);
    a[cr].ls=++tot;build(l,mid,tot);
    a[cr].rs=++tot;build(mid+1,r,tot);
    pushup(cr);
}
void mdf(int k,int d)
{
    a[k].b[d]=1;a[k].b[!d]=0;a[k].rev=0;//b[0]和b[1]不同时存在 
    a[k].sum=a[k].cd*d;
    a[k].len[d]=a[k].l[d]=a[k].r[d]=a[k].cd;
    a[k].len[!d]=a[k].l[!d]=a[k].r[!d]=0;
}
void rv(int k)
{
    a[k].rev^=1;//和mdf一样,把下传标记写在函数里 且是^=1 
    if(a[k].b[0]||a[k].b[1])a[k].rev=0,swap(a[k].b[0],a[k].b[1]);//rev和b不同时存在 
    a[k].sum=a[k].cd-a[k].sum;swap(a[k].len[1],a[k].len[0]);
    swap(a[k].l[0],a[k].l[1]);swap(a[k].r[0],a[k].r[1]);
}
void pushdown(int cr)
{
    if(!a[cr].ls)return;
    int ls=a[cr].ls,rs=a[cr].rs;
    if(a[cr].rev)
        {a[cr].rev=0;rv(ls);rv(rs);a[cr].rev=0;}
    if(a[cr].b[0]||a[cr].b[1])
        {int d=a[cr].b[1];a[cr].b[d]=0;mdf(ls,d);mdf(rs,d);}
}
void mdfy(int l,int r,int cr,int d)
{
    if(l>=L&&r<=R){mdf(cr,d);return;}
    pushdown(cr);
    int mid=((l+r)>>1);
    if(mid>=L)mdfy(l,mid,a[cr].ls,d);
    if(mid<R)mdfy(mid+1,r,a[cr].rs,d);
    pushup(cr);
}
void rever(int l,int r,int cr)
{
    if(l>=L&&r<=R){
        rv(cr);return;
    }
    pushdown(cr);
    int mid=((l+r)>>1);
    if(mid>=L)rever(l,mid,a[cr].ls);
    if(mid<R)rever(mid+1,r,a[cr].rs);
    pushup(cr);
}
int query(int l,int r,int cr)
{
    if(l>=L&&r<=R)return a[cr].sum;
    pushdown(cr);
    int mid=((l+r)>>1),ret=0;
    if(mid>=L)ret+=query(l,mid,a[cr].ls);
    if(mid<R)ret+=query(mid+1,r,a[cr].rs);
    return ret;
}
int lnk(int l,int r,int cr)
{
    if(l>=L&&r<=R)return a[cr].len[1];
    pushdown(cr);
    int mid=((l+r)>>1),ls=a[cr].ls,rs=a[cr].rs;
    if(mid<L)return lnk(mid+1,r,rs);
    if(mid>=R)return lnk(l,mid,ls);
    int tp=min(a[ls].r[1],mid-L+1)+min(a[rs].l[1],R-mid);
    return max(max(lnk(l,mid,ls),lnk(mid+1,r,rs)),tp);//
}
int main()
{
    n=rdn();m=rdn();for(int i=1;i<=n;i++)c[i]=rdn();
    build(1,n,1);int op;
    while(m--)
    {
        op=rdn();L=rdn()+1;R=rdn()+1;
        if(op<=1)mdfy(1,n,1,op);
        if(op==2)rever(1,n,1);
        if(op==3)printf("%d
",query(1,n,1));
        if(op==4)printf("%d
",lnk(1,n,1));
    }
    return 0;
}

 

以上是关于bzoj1858[Scoi2010]序列操作的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1858 [Scoi2010]序列操作

bzoj千题计划177:bzoj1858: [Scoi2010]序列操作

BZOJ_1858_[Scoi2010]序列操作_线段树

bzoj1858[Scoi2010]序列操作

bzoj 1858: [Scoi2010]序列操作

BZOJ 1858 SCOI2010 序列操作 线段树