BZOJ 1858: [Scoi2010]序列操作 [线段树]

可恶两个标记传反顺序了一直到现在....

睡觉了睡觉了

这是我写过最漂亮的线段树


 

[补题解]

想法很简单的线段树,同时维护0,1两个信息

因为要求最长0,1序列所以要维护最长,从左开始最长,从右开始最长

然后为了转移还要维护一个区间长度(该死一开始没维护这个长度后来有的地方加上有的地方没加然后一堆bug改了好久)

我用了合并和返回节点的方法,要不然写三个询问太恶心了

关于两个标记,显然打修改标记时要清空翻转标记,我打翻转标记时把修改标记也翻转了,所以下传标记如果先修改后翻转的话就成“翻转了两次”啊啊啊啊啊啊啊啊,以后一定要想清楚

以后要多独立写几道复杂的题增强玛丽!

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define lc x<<1
#define rc x<<1|1
#define mid ((l+r)>>1)
#define lson lc,l,mid
#define rson rc,mid+1,r
const int N=1e5+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int n,Q,op,a,b;
struct Node{
    int mx[2],lm[2],rm[2],sum[2];
    int tag,rev;
    int len;
    Node():tag(-1),rev(0),len(0){mx[0]=mx[1]=lm[0]=lm[1]=rm[0]=rm[1]=sum[0]=sum[1]=0;}
}t[N<<2];

inline Node Merge(Node a,Node b){
    Node re;
    re.sum[1]=a.sum[1]+b.sum[1];
    re.mx[1]=max( a.rm[1]+b.lm[1] , max(a.mx[1],b.mx[1]) );
    re.lm[1]=a.lm[1]+ (a.lm[1]==a.len ? b.lm[1] : 0);
    re.rm[1]=b.rm[1]+ (b.rm[1]==b.len ? a.rm[1] : 0);

    re.sum[0]=a.sum[0]+b.sum[0];
    re.mx[0]=max( a.rm[0]+b.lm[0] , max(a.mx[0],b.mx[0]) );
    re.lm[0]=a.lm[0]+ (a.lm[0]==a.len ? b.lm[0] : 0);
    re.rm[0]=b.rm[0]+ (b.rm[0]==b.len ? a.rm[0] : 0);

    re.len=a.len+b.len;
    return re;
}
inline void pushUp(int x){t[x]=Merge(t[lc],t[rc]);}

void paint(int x,int v){
    t[x].tag=v;
    t[x].rev=0;
    t[x].sum[v]=t[x].mx[v]=t[x].lm[v]=t[x].rm[v]=t[x].len;
    v^=1;
    t[x].sum[v]=t[x].mx[v]=t[x].lm[v]=t[x].rm[v]=0;
}
void rever(int x){
    t[x].rev^=1;
    if(t[x].tag!=-1) t[x].tag^=1;
    swap(t[x].sum[0],t[x].sum[1]);
    swap(t[x].mx[0] ,t[x].mx[1]);
    swap(t[x].lm[0] ,t[x].lm[1]);
    swap(t[x].rm[0] ,t[x].rm[1]);
}

void pushDown(int x){
    if(t[x].rev){
        rever(lc);
        rever(rc);
        t[x].rev=0;
    }
    if(t[x].tag!=-1){
        paint(lc,t[x].tag);
        paint(rc,t[x].tag);
        t[x].tag=-1;
    }
}

void build(int x,int l,int r){
    if(l==r) t[x].len=1,paint(x,read());
    else{
        build(lson);
        build(rson);
        pushUp(x);
    }
}

void segCov(int x,int l,int r,int ql,int qr,int v){
    if(ql<=l&&r<=qr) paint(x,v);
    else{
        pushDown(x);
        if(ql<=mid) segCov(lson,ql,qr,v);
        if(mid<qr) segCov(rson,ql,qr,v);
        pushUp(x);
    }
}

void segRev(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr) rever(x);
    else{
        pushDown(x);
        if(ql<=mid) segRev(lson,ql,qr);
        if(mid<qr) segRev(rson,ql,qr);
        pushUp(x);
    }
}

int segSum(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr) return t[x].sum[1];
    else{
        pushDown(x);
        int ans=0;
        if(ql<=mid) ans+=segSum(lson,ql,qr);
        if(mid<qr) ans+=segSum(rson,ql,qr);
        return ans;
    }
}

Node segQue(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr) return t[x];
    else{
        pushDown(x);
        if(qr<=mid) return segQue(lson,ql,qr);
        if(mid<ql) return segQue(rson,ql,qr);
        return Merge(segQue(lson,ql,qr),segQue(rson,ql,qr));
    }
}

int main(){
    freopen("in","r",stdin);
    n=read();Q=read();
    build(1,1,n);
    while(Q--){
        op=read();a=read()+1;b=read()+1;
        if(op==0)       segCov(1,1,n,a,b,0);
        else if(op==1) segCov(1,1,n,a,b,1);
        else if(op==2) segRev(1,1,n,a,b);
        else if(op==3) printf("%d\n",segSum(1,1,n,a,b));
        else if(op==4) printf("%d\n",segQue(1,1,n,a,b).mx[1]);
    }
}

 

posted @ 2017-03-02 00:24  Candy?  阅读(216)  评论(0编辑  收藏  举报