splay模板


bzoj1251 序列终结者

题意:

有一个长度为n的序列,初始情况下每个数的值为0
接下来有m次操作,每次操作为下面三种的其中一种:
(1,L,R,V),将区间[L,R]内的每个数加上V
(2,L,R),将区间[L,R]翻转
(3,L,R),输出[L,R]的最大值

数据范围:n<=5e4,m<=1e5

code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
const int inf=-1e9;
struct Spaly{
    struct Node{
        int val,Max,add,Size,son[2];
        bool rev;
        void init(int _val){
            val=Max=_val;
            Size=1;
            add=rev=son[0]=son[1]=0;
        }
    }T[maxm];
    int fa[maxm],root;
    void pushup(int x){
        T[x].Max=T[x].val,T[x].Size=1;
        if(T[x].son[0]){
            T[x].Max=max(T[x].Max,T[T[x].son[0]].Max);
            T[x].Size+=T[T[x].son[0]].Size;
        }
        if(T[x].son[1]){
            T[x].Max=max(T[x].Max,T[T[x].son[1]].Max);
            T[x].Size+=T[T[x].son[1]].Size;
        }
    }
    void pushdown(int x){
        if(x==0)return ;
        if(T[x].add){
            if(T[x].son[0]){
                T[T[x].son[0]].val+=T[x].add;
                T[T[x].son[0]].Max+=T[x].add;
                T[T[x].son[0]].add+=T[x].add;
            }
            if(T[x].son[1]){
                T[T[x].son[1]].val+=T[x].add;
                T[T[x].son[1]].Max+=T[x].add;
                T[T[x].son[1]].add+=T[x].add;
            }
            T[x].add=0;
        }
        if(T[x].rev){
            if(T[x].son[0])T[T[x].son[0]].rev^=1;
            if(T[x].son[1])T[T[x].son[1]].rev^=1;
            swap(T[x].son[0],T[x].son[1]);
            T[x].rev=0;
        }
    }
    void Rotate(int x,int kind){//kind=0左旋,=1右旋
        int y=fa[x],z=fa[y];
        T[y].son[!kind]=T[x].son[kind],fa[T[x].son[kind]]=y;
        T[x].son[kind]=y,fa[y]=x;
        T[z].son[T[z].son[1]==y]=x,fa[x]=z;
        pushup(y);
    }
    void Splay(int x,int goal){//将x旋转到goal位置
        if(x==goal)return ;
        while(fa[x]!=goal){
            int y=fa[x],z=fa[y];
            pushdown(z),pushdown(y),pushdown(x);
            int rx=T[y].son[0]==x,ry=T[z].son[0]==y;//rx,ry,=0左儿子,=1右儿子
            if(z==goal)Rotate(x,rx);
            else{
                if(rx==ry)Rotate(y,ry);
                else Rotate(x,rx);
                Rotate(x,ry);
            }
        }
        pushup(x);
        if(goal==0)root=x;
    }
    int Select(int pos){//找pos的位置
        int u=root;
        pushdown(u);
        while(T[T[u].son[0]].Size!=pos){
            if(pos<T[T[u].son[0]].Size)u=T[u].son[0];//左边
            else{//右边
                pos-=T[T[u].son[0]].Size+1;
                u=T[u].son[1];
            }
            pushdown(u);
        }
        return u;
    }
    void update(int L,int R,int val){
        int u=Select(L-1),v=Select(R+1);
        Splay(u,0);
        Splay(v,u);
        T[T[v].son[0]].Max+=val;
        T[T[v].son[0]].val+=val;
        T[T[v].son[0]].add+=val;
    }
    void Reverse(int L,int R){
        int u=Select(L-1),v=Select(R+1);
        Splay(u,0);
        Splay(v,u);
        T[T[v].son[0]].rev^=1;
    }
    int query(int L,int R){
        int u=Select(L-1),v=Select(R+1);
        Splay(u,0);
        Splay(v,u);
        return T[T[v].son[0]].Max;
    }
    int build(int L,int R){
        if(L>R)return 0;
        if(L==R)return L;
        int mid=(L+R)/2,sL,sR;
        T[mid].son[0]=sL=build(L,mid-1);
        T[mid].son[1]=sR=build(mid+1,R);
        fa[sL]=fa[sR]=mid;
        pushup(mid);
        return mid;
    }
    void init(int n){
        T[0].init(-inf),T[1].init(-inf),T[n+2].init(-inf);
        for(int i=2;i<=n+1;i++)T[i].init(0);
        root=build(1,n+2),fa[root]=0;
        fa[0]=0,T[0].son[1]=root,T[0].Size=0;
    }
}T;
int n,m;
signed main(){
    scanf("%d%d",&n,&m);
    T.init(n);
    while(m--){
        int d;scanf("%d",&d);
        if(d==1){//区间加
            int l,r,v;scanf("%d%d%d",&l,&r,&v);
            T.update(l,r,v);
        }else if(d==2){//区间翻转
            int l,r;scanf("%d%d",&l,&r);
            T.Reverse(l,r);
        }else if(d==3){//区间最值
            int l,r;scanf("%d%d",&l,&r);
            int ans=T.query(l,r);
            printf("%d\n",ans);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值