【BZOJ】1251: 序列终结者

【题意】给定含有n个0的的数列。

1.区间加值

2.区间翻转

3.区间求最大值

【算法】平衡树(fhq-treap)

需要特别注意的是:

1.使0点对全局无影响并全程保持(例如求max,t[0].mx=-inf)

2.平衡树和线段树的上传区别在于要考虑本身这个点。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct tree{int l,r,rnd,num,mx,add,delta,sz;}t[maxn*2];
int st[maxn];
int n,m,root;
void down(int k){
    if(t[k].delta){
        swap(t[k].l,t[k].r);
        if(t[k].l)t[t[k].l].delta^=1;
        if(t[k].r)t[t[k].r].delta^=1;
        t[k].delta=0;
    }
    if(t[k].add){
        int p=t[k].add;
        if(t[k].l)t[t[k].l].add+=p,t[t[k].l].mx+=p,t[t[k].l].num+=p;
        if(t[k].r)t[t[k].r].add+=p,t[t[k].r].mx+=p,t[t[k].r].num+=p;//keep 0->0!!!
        t[k].add=0;
    }
}
int max(int a,int b){return a<b?b:a;}
void up(int k){//different from sgt!
    t[k].mx=max(t[k].num,max(t[t[k].l].mx,t[t[k].r].mx));
    t[k].sz=1+t[t[k].l].sz+t[t[k].r].sz;
}
void dfs(int k){
    if(!k)return;
    dfs(t[k].l);
    dfs(t[k].r);
    up(k);
}
void build(){
    int top=0;
    for(int i=1;i<=n;i++){
        t[i]=(tree){0,0,rand(),0,0,0,0,1};
        while(top&&t[st[top]].rnd>t[i].rnd){
            t[st[top]].r=t[i].l;
            t[i].l=st[top--];
        }
        t[st[top]].r=i;
        st[++top]=i;
    }
    dfs(st[1]);
    t[0].r=0;
    t[0].mx=-0x3f3f3f3f;//make 0 no influence
    root=st[1];
}
int merge(int a,int b){
    if(!a||!b)return a^b;
    if(t[a].rnd<t[b].rnd){
        down(a);
        t[a].r=merge(t[a].r,b);
        up(a);
        return a;
    }
    else{
        down(b);
        t[b].l=merge(a,t[b].l);
        up(b);
        return b;
    }
}
void split(int k,int &l,int &r,int x){
    if(!k)return void(l=r=0);
    down(k);
    if(x<t[t[k].l].sz+1){
        r=k;
        split(t[k].l,l,t[k].l,x);
    }
    else{
        l=k;
        split(t[k].r,t[k].r,r,x-t[t[k].l].sz-1);
    }
    up(k);
}
void plus(int l,int r,int x){
    int a,b,c;
    split(root,b,c,r);
    split(b,a,b,l-1);
    t[b].add+=x;t[b].mx+=x;t[b].num+=x;
    root=merge(a,b);root=merge(root,c);
}
void turn(int l,int r){
    int a,b,c;
    split(root,b,c,r);split(b,a,b,l-1);
    t[b].delta^=1;
    root=merge(a,b);root=merge(root,c);
}
int ask(int l,int r){
    int a,b,c,ans;
    split(root,b,c,r);split(b,a,b,l-1);
    ans=t[b].mx;
    root=merge(a,b);root=merge(root,c);
    return ans;
}
int main(){
    srand(233);
    scanf("%d%d",&n,&m);
    build();
    for(int i=1;i<=m;i++){
        int k,l,r,x;
        scanf("%d%d%d",&k,&l,&r);
        if(l>r)continue;
        if(k==1){
            scanf("%d",&x);
            plus(l,r,x);
        }
        else if(k==2)turn(l,r);
        else printf("%d\n",ask(l,r));
    }
    return 0;
}
View Code

 

posted @ 2017-11-24 21:19  ONION_CYC  阅读(343)  评论(0编辑  收藏  举报