splay的模版

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAXN 100010
struct Node{
    int key, sz, cnt; //cnt表示结点值为key的结点的数量
    Node *ch[2], *pnt;//左右儿子和父亲
    Node(){} //给Node函数赋值。
    Node(int x, int y, int z){
    key = x, sz = y, cnt = z;
    }
    void rs(){//这个函数的含义就是旋转后,这2个结点的大小已经发生了改变
    sz = ch[0]->sz + ch[1]->sz + cnt;
    }
}nil(0, 0, 0), *NIL = &nil;
struct Splay{//伸展树结构体类型
    Node *root;
    int ncnt;//计算key值不同的结点数,注意已经去重了*
    Node nod[MAXN];
    void init(){// 首先要初始化*
        root = NIL;
        ncnt = 0;
    }
    void rotate(Node *x, bool d){//旋转操作,d为true表示右旋
        Node *y = x->pnt;
        y->ch[!d] = x->ch[d];//x右旋的时候,y的左儿子为x的右边儿
        if (x->ch[d] != NIL)//如果x的右儿子不为空那么这个右儿子的父亲是y
            x->ch[d]->pnt = y;
        x->pnt = y->pnt;//把y的父亲赋值给x的父亲,相当x替代了y的位子
        if (y->pnt != NIL){//把y的父亲的左儿子或右儿子从y改为x
            if (y == y->pnt->ch[d])
                y->pnt->ch[d] = x;
            else
                y->pnt->ch[!d] = x;
        }
        x->ch[d] = y;
        y->pnt = x;
        y->rs();
        x->rs();
    }
    void splay(Node *x, Node *target){//将x伸展到target的儿子位置处
        Node *y;
        while (x->pnt != target){ //当target时,就转x为根结点
            y = x->pnt;
            if (x == y->ch[0]){
                if (y->pnt != target && y == y->pnt->ch[0])//如果x是y的左结点,且y的父亲结点不是目标结点
                    rotate(y, true);//并且y是y的左结点才旋转y否则旋转x
                    rotate(x, true);
            }
            else{
                if (y->pnt != target && y == y->pnt->ch[1])
                    rotate(y, false);
                    rotate(x, false);
            }
        }
        if (target == NIL)
            root = x;
    }
    /************************以上一般不用修改************************/
    void insert(int key){//插入一个值
        if (root == NIL){//初始化根节点
            ncnt = 0;
            root = &nod[++ncnt];
            root->ch[0] = root->ch[1] = root->pnt = NIL;
            root->key = key; //这里表示这个结点的值
            root->sz = root->cnt = 1;//sz表示这个结点作为根的大小
            return;
        }
        Node *x = root, *y;
        while (1){  //从x开始向下找,刚开始x就是root
            x->sz++;
            if (key == x->key){
                x->cnt++;
                x->rs();
                y = x;
                break;
            }
            else if (key < x->key){//这里表示如果新加入的值比x小,且左结点为空,那么就加入其作为左儿子
                    if (x->ch[0] != NIL)//否则接着往左边找
                        x = x->ch[0];
                    else{//且左结点为空,那么就加入其作为左儿子
                        x->ch[0] = &nod[++ncnt];
                        y = x->ch[0];//新加入的点为y
                        y->key = key;
                        y->sz = y->cnt = 1;//y的刚开始大小为1
                        y->ch[0] = y->ch[1] = NIL;//左右子树均为NIL
                        y->pnt = x;//
                        break;
                    }
            }
            else{
                if (x->ch[1] != NIL)
                    x = x->ch[1];
                else{
                    x->ch[1] = &nod[++ncnt];
                    y = x->ch[1];
                    y->key = key;
                    y->sz = y->cnt = 1;
                    y->ch[0] = y->ch[1] = NIL;
                    y->pnt = x;
                    break;
                }
            }
        }
        splay(y, NIL);
    }
    Node* search(int key){//查找一个值并且把这个值旋上来,返回指针
        if (root == NIL)
            return NIL;
        Node *x = root, *y = NIL;
        while (1){
            if (key == x->key){
                y = x;
                break;
            }
            else if (key > x->key){
                if (x->ch[1] != NIL)
                x = x->ch[1];
                else
                    break;
            }
            else{
                if (x->ch[0] != NIL)
                    x = x->ch[0];
                else
                    break;
            }
        }
        splay(x, NIL);
        return y;
    }
    Node* searchmin(Node *x){//查找最小值,返回指针
        Node *y = x->pnt;
        while (x->ch[0] != NIL){//遍历到最左的儿子就是最小值
            x = x->ch[0];
        }
            splay(x, y);
            return x;
    }
    void del(int key){//删除一个值
        if (root == NIL)
            return;
        Node *x = search(key), *y;
        if (x == NIL)
            return;
        if (x->cnt > 1){ //如果这个结点还有,那么它就变成根结点
            x->cnt--;
            x->rs();
            return;
        }
        else if (x->ch[0] == NIL && x->ch[1] == NIL){ //这个是最后一个结点
            init();
            return;
        }
        else if (x->ch[0] == NIL){
            root = x->ch[1];
            x->ch[1]->pnt = NIL;
            return;
        }
        else if (x->ch[1] == NIL){
            root = x->ch[0];
            x->ch[0]->pnt = NIL;
            return;
        }
        y = searchmin(x->ch[1]);
        y->pnt = NIL;
        y->ch[0] = x->ch[0];
        x->ch[0]->pnt = y;
        y->rs();
        root = y;
    }
    int rank(int key){//???这里看不懂,求结点高度
        Node *x = search(key);
        if (x == NIL)
            return 0;
        return x->ch[0]->sz + 1;/* or x->cnt*/
    }
    Node* findk(int kth){//查找第k小的值
        if (root == NIL || kth > root->sz)
            return NIL;
        Node *x = root;
        while (1){
            if (x->ch[0]->sz +1 <= kth && kth <= x->ch[0]->sz + x->cnt)
                break;
            else if (kth <= x->ch[0]->sz)
                x = x->ch[0];
            else{
                kth -= x->ch[0]->sz + x->cnt;
                x = x->ch[1];
            }
        }
        splay(x, NIL);
        return x;
    }
}sp;
int main(){ //每次sp的返回都是一个指针
    sp.init();
    sp.insert(10);
    sp.insert(2);
    sp.insert(2);
    sp.insert(2);
    sp.insert(3);
    sp.insert(3);
    sp.insert(10);
    for (int i = 1; i <= 7; i++)
        cout << sp.findk(i)->key << endl;
    cout<< "最小值是"<<sp.searchmin(sp.root)->key<<endl;
    sp.del(2);
    sp.del(3);
    sp.del(1);
    cout << "不同结点的数量"<<sp.ncnt << endl;
    cout << "这棵树的大小 " << sp.root->sz << endl;
    return 0;
}

这个代码是一个模版。

下面是区间求最大值,反转

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int N=100005, INF=0x7fffffff;

struct Splay_Tree {
    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[N];
    int fa[N], 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) {
        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) {
        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;
            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;
    scanf("%d%d", &n, &m);
    hehe.init(n);
    for(int i=0, a, b, c, d; i<m; i++) {
        scanf("%d", &a);
        if(a==1) {
            scanf("%d%d%d", &b, &c, &d);
            hehe.update(b, c, d);
        }
        else if(a==2) {
            scanf("%d%d", &b, &c);
            hehe.Reverse(b, c);
        }
        else {
            scanf("%d%d", &b, &c);
            printf("%d\n", hehe.query(b, c));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值