Splay 模版

网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列 要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目 就叫序列终结者吧。 【问题描述】 给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V。 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。 3. 求[L,R]这个区间中的最大值。 最开始所有元素都是0。

Input

第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。

Output

对于每个第3种操作,给出正确的回答。

Sample Input
4 4
1 1 3 2
1 2 4 -1
2 1 3

3 2 4

2

#include <bits/stdc++.h>
//#include <ext/pb_ds/tree_policy.hpp>
//#include <ext/pb_ds/assoc_container.hpp>
//using namespace __gnu_pbds;
using namespace std;



#define pi acos(-1)
#define endl '\n'
#define me(x) memset(x,0,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0);
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,-1,-1,1,1};
const int dy[]={0,1,0,-1,1,-1,1,-1};
const int maxn=1e3+5;
const int maxx=1e5+100;
const double EPS=1e-7;
const int MOD=1000000007;
#define mod(x) ((x)%MOD);
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
//typedef tree<pt,null_type,less< pt >,rb_tree_tag,tree_order_statistics_node_update> rbtree;
/*lch[root] = build(L1,p-1,L2+1,L2+cnt);
    rch[root] = build(p+1,R1,L2+cnt+1,R2);中前*/
/*lch[root] = build(L1,p-1,L2,L2+cnt-1);
    rch[root] = build(p+1,R1,L2+cnt,R2-1);中后*/
long long gcd(long long a , long long b){if(b==0) return a;a%=b;return gcd(b,a);}

struct Splay_Tree
{
    struct node
    {
        int val,Max,add,Size,son[2];//add =lazy val为节点的值 Max节点最大值
        //Size 节点大小,son为儿子
        bool rev;//节点是否翻转
        void init(int _val)
        {
            val=Max=_val;
            Size=1;
            add=rev=son[0]=son[1]=0;
        }
    }T[maxx];
    int fa[maxx],root;//fa是节点的父亲,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)//如果有lazy的话
        {
            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)
    {
        int y=fa[x],z=fa[y];
        T[y].son[!kind]=T[x].son[kind],fa[T[x].son[kind]]=y;//B
        T[x].son[kind]=y,fa[y]=x;//y
        T[z].son[T[z].son[1]==y]=x,fa[x]=z;//z
        pushUp(y);
    }//kind 为1是 !kind==0 T[y]的左儿子变成了T[x]的右儿子
    //zig zag的合并
    void Splay(int x,int goal)
    {
        if(x==goal) return ;//goal  是根
        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==1 左儿子
            //rx==0 右儿子
            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)
    {
        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)>>1,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;
    }
};

Splay_Tree hehe;
int main()
{
    int n,m;
    cin>>n>>m;
    hehe.init(n);
    for(int i=0,a,b,c,d;i<m;i++)
    {
        cin>>a;
        if(a==1)
        {
            cin>>b>>c>>d;
            hehe.update(b,c,d);
        }
        else if(a==2)
        {
            cin>>b>>c;
            hehe.Reverse(b,c);
        }
        else
        {
            cin>>b>>c;
            printf("%d\n",hehe.query(b,c));
        }
    }
}


















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值