[BZOJ1251]序列终结者

本文介绍了一种基于Splay树的数据结构实现,能够高效地完成区间加、区间翻转和查询区间最大值等操作。文章通过具体代码展示了Splay树的节点结构、旋转、翻转等关键操作,并提供了完整的实现细节。

原题地址

维护一个序列,要求支持区间加、区间翻转、区间最值.

复习Splay…

手感极差,写+调了1h,感觉药丸…

AC code:

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=100010;
const int INF=1<<29;
int n,m,tot;

struct nod{
    int  v,mx,siz,tad;
    bool rev;
    nod  *pr,*ch[2];
}*NIL,pool[N];

struct Splay{
    nod *root;

    Splay(){
        NIL=root=&pool[tot++];
        NIL->v=NIL->mx=-INF;
        for(int i=0;i<=n+1;i++) insert(&root,NIL,0);
    }
    nod* newnod(nod *pre,int v){
        nod *p=&pool[tot++];
        p->v=p->mx=v;p->siz=1;
        p->pr=pre;p->ch[0]=p->ch[1]=NIL;
        return p;
    }
    void update(nod *p){
        if(p==NIL) return ;
        p->siz=p->ch[0]->siz+p->ch[1]->siz+1;
        p->mx=max(p->v,max(p->ch[0]->mx,p->ch[1]->mx));
    }
    void clear(nod *p){
        if(p==NIL||p==NULL) return ;
        if(p->tad){
            p->v+=p->tad;p->mx+=p->tad;
            p->ch[0]->tad+=p->tad;p->ch[1]->tad+=p->tad;
            p->tad=0;
        }
        if(p->rev){
            nod *t=p->ch[0];p->ch[0]=p->ch[1];p->ch[1]=t;
            p->ch[0]->rev^=1;p->ch[1]->rev^=1;p->rev=0;
        }
    }
    void rotate(nod *x,bool t){
        nod *y=x->pr,*z=y->pr,*b=x->ch[t^1];
        b->pr=y;y->pr=x;x->pr=z;y->ch[t]=b;x->ch[t^1]=y;
        if(z->ch[0]==y) z->ch[0]=x;
        if(z->ch[1]==y) z->ch[1]=x;
        clear(y->ch[0]);clear(y->ch[1]);clear(x->ch[t]);update(y);update(x);
    }
    void splay(nod *x,nod *obj){
        while(x->pr!=obj){
            nod *y=x->pr,*z=y->pr;
            if(z==obj&&y->ch[0]==x) rotate(x,0);
            else if(z==obj&&y->ch[1]==x) rotate(x,1);
            else if(z->ch[0]==y&&y->ch[0]==x){rotate(y,0);rotate(x,0);}
            else if(z->ch[1]==y&&y->ch[1]==x){rotate(y,1);rotate(x,1);}
            else if(z->ch[1]==y){rotate(x,0);rotate(x,1);}
            else{rotate(x,1);rotate(x,0);}
        }
        if(obj==NIL) root=x;
    }
    void insert(nod **p,nod *pre,int v){
        if(*p==NIL){
            *p=newnod(pre,v);
            splay(*p,NIL);
            return ;
        }
        (*p)->siz++;
        insert(&(*p)->ch[0],*p,v);
    }
    nod* getkth(int k){
        clear(root);
        nod *p=root;
        int rk=p->ch[0]->siz+1;
        while(rk!=k){
            if(rk>k){
                p=p->ch[0];
                clear(p);
                rk-=p->ch[1]->siz+1;
            }
            else{
                p=p->ch[1];
                clear(p);
                rk+=p->ch[0]->siz+1;
            }
        }
        return p;
    }
    void add(int L,int R,int v){
        splay(getkth(L),NIL);
        splay(getkth(R+2),root);
        root->ch[1]->ch[0]->tad+=v;
        clear(root->ch[1]->ch[0]);clear(root->ch[1]->ch[1]);clear(root->ch[0]);
        update(root->ch[1]);update(root);
    }
    void rvs(int L,int R){
        splay(getkth(L),NIL);
        splay(getkth(R+2),root);
        root->ch[1]->ch[0]->rev^=1;
    }
    void getmax(int L,int R){
        splay(getkth(L),NIL);
        splay(getkth(R+2),root);
        clear(root->ch[1]->ch[0]);
        printf("%d\n",root->ch[1]->ch[0]->mx);
    }
};

int main(){
    scanf("%d%d",&n,&m);
    Splay T;
    for(int i=1;i<=m;i++){
        int k,L,R,v;
        scanf("%d",&k);
        if(k==1){
            scanf("%d%d%d",&L,&R,&v);
            T.add(L,R,v);
        }
        else if(k==2){
            scanf("%d%d",&L,&R);
            T.rvs(L,R);
        }
        else{
            scanf("%d%d",&L,&R);
            T.getmax(L,R);
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值