bzoj 1858 序列操作

来源:互联网 发布:中联软件靠谱吗 编辑:程序博客网 时间:2024/06/06 20:17

有毒的线段树

一个01序列,支持以下操作

0 a b 把[a, b]区间内的所有数全变成0
1 a b 把[a, b]区间内的所有数全变成1
2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0
3 a b 询问[a, b]区间内总共有多少个 1
4 a b 询问[a, b]区间内最多有多少个连续的 1 


先不考虑操作3

线段树的节点要维护

从左端点开始连续的1的个数 lmax

从右端点开始连续的1的个数 rmax

当前区间最长的连续的1的长度 ma

当前区间1的个数 sum

当前区间是否都是1 all

合并的时候不妨设左右区间分别为L,R

如果L.alllmax=L.sum+R.lmax

否则lmax=L.lmax

rmax同理

ma=max(max(L.ma,R.ma),L.rmax+R.lmax)

弱化的题目大概这样就可以了


然后取反的怎么做呢?

是不是同时维护一下对于0的这五个值,取反的时候直接交换就可以了

同时我们发现当前区间都是1等价于0的个数为0,所以维护四个值就好

另外值得注意的是这里线段树支持的两个操作(取反,覆盖)是不独立的

也就是取反的时候不能直接覆盖lazy,而要由原来的lazy计算新的lazy

具体见代码

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 112345;struct Info{    int v[2][4]; // lma max rma sum    void maintain(int val){        if(val<=1){            int all = v[0][3]+v[1][3];            for(int i=0;i<4;i++)                v[1^val][i] = 0,v[val][i] = all;        }        else{            for(int i=0;i<4;i++) swap(v[0][i],v[1][i]);        }    }    void clear(){        memset(v,0,sizeof(v));    }    void init(){        memset(v,0,sizeof(v));        for(int i=0;i<4;i++)            v[0][i] = 1;    }    void out(){        puts("----------------------st");        for(int i=0;i<=1;i++){            printf("%d : (ls %d ma %d rs %d) sum = %d\n",i,v[i][0],v[i][1],v[i][2],v[i][3]);        }        puts("-----------------------here");    }};Info operator + (const Info & L,const Info & R){    Info ret;    ret.clear();    for(int i=0;i<=1;i++){        ret.v[i][3] = L.v[i][3] + R.v[i][3];        ret.v[i][0] = L.v[i][0]; if(L.v[i^1][3]==0) ret.v[i][0] += R.v[i][0];        ret.v[i][2] = R.v[i][2]; if(R.v[i^1][3]==0) ret.v[i][2] += L.v[i][2];        ret.v[i][1] = max(L.v[i][1],R.v[i][1]);        ret.v[i][1] = max(ret.v[i][1],L.v[i][2]+R.v[i][0]);    }    return ret;}#define lson o<<1,l,m#define rson o<<1|1,m+1,r#define root 1,1,n#define Now int o,int l,int r#define Mid int m=l + (r-l)/2Info val[maxn*4];int lazy[maxn*4];int chag(int x){    if(x==-1) return 2;    if(x<2) return x^1;    return -1;}void push_down(Now){    int v = lazy[o];    lazy[o] = -1;    if(l==r) return;    val[o<<1].maintain(v);    val[o<<1|1].maintain(v);    if(v<=1){        lazy[o<<1] = lazy[o<<1|1] = v;    }    else{        lazy[o<<1] = chag(lazy[o<<1]);        lazy[o<<1|1] = chag(lazy[o<<1|1]);    }}void update(Now,int ul,int ur,int v){    if(ul <= l && r <= ur){        if(v<=1) lazy[o] = v;        else     lazy[o] = chag(lazy[o]);        val[o].maintain(v);        return;    }    Mid;    if(lazy[o]!=-1) push_down(o,l,r);    if(ul <= m){        update(lson,ul,ur,v);    }    if(m+1<=ur){        update(rson,ul,ur,v);    }    val[o] = val[o<<1] + val[o<<1|1];}Info query(Now,int ql,int qr){    if(ql <= l && r <= qr){        return val[o];    }    Info ret;    ret.clear();    if(lazy[o]!=-1){        push_down(o,l,r);    }    Mid;    if(ql <= m)ret = query(lson,ql,qr) + ret;    if(m+1<=qr)ret = ret + query(rson,ql,qr);    return ret;}void buildtree(Now){    if(l!=r){        Mid;        buildtree(lson);        buildtree(rson);        val[o] = val[o<<1] + val[o<<1|1];    }    else val[o].init();}int main(){    int n,m;    while(~scanf("%d %d",&n,&m)){        int v;        memset(lazy,-1,sizeof(lazy));        buildtree(root);        for(int i=1;i<=n;i++){            scanf("%d",&v);            update(root,i,i,v);        }        int l,r;        while(m--){            scanf("%d %d %d",&v,&l,&r);            l++,r++;            if(v<=2) update(root,l,r,v);            else{                if(v == 3) printf("%d\n",query(root,l,r).v[1][3]);                else       printf("%d\n",query(root,l,r).v[1][1]);            }        }    }    return 0;}
0 0
原创粉丝点击