P3369 【模板】普通平衡树 (splay)

splay支持查询

1.第k大

2.第k大是谁

3.数的前驱

4.数的后继

5.添加删除

#include <bits/stdc++.h>
using namespace std;

int rt, cnt;
int ch[100005][2];    //左右儿子
int fa[100005];       //父节点
int sz[100005];       //字树和
int cn[100005];       //当前点出现了多少次
int val[100005];      //当前点权值

void clear(int x) {
    sz[x] = fa[x] = ch[x][0] = ch[x][1] = cn[x] = val[x] = 0;
}

bool ws(int x) {  //which son
    return ch[fa[x]][1] == x;  // 右儿子1 左儿子0
}

void update(int x) {
    if(x) {
        sz[x] = cn[x];
        if(ch[x][0]) sz[x] += sz[ch[x][0]];
        if(ch[x][1]) sz[x] += sz[ch[x][1]];
    }
}

void setfa(int x, int f, int d) {
    if(x != 0) fa[x] = f;
    if(f != 0) ch[f][d] = x;
}

void rot(int x) {
    int f = fa[x]; int ff = fa[f]; int s1 = ws(x); int s2 = ws(f);
    int p = ch[x][s1 ^ 1];
    setfa(p, f, s1);
    setfa(f, x, s1 ^ 1);
    setfa(x, ff, s2);
    update(f);
    update(x);
}

void splay(int x) {
    for(; fa[x]; rot(x))
        if(fa[fa[x]] && ws(x) == ws(fa[x])) rot(fa[x]);
    rt = x;
}

void inser(int x) {
    if(rt == 0) {
        cnt++; ch[cnt][0] = ch[cnt][1] = fa[cnt] = 0;
        val[cnt] = x;
        cn[cnt] = 1;
        sz[cnt] = 1;
        rt = cnt;
        return;
    }

    int now = rt, f = 0;
    while(1) {
        if(val[now] == x) {
            cn[now]++; update(now); update(f);
            splay(now);
            break;
        }

        f = now;
        now = ch[now][val[now] < x];
        if(now == 0) {
            cnt++;
            val[cnt] = x;
            cn[cnt] = sz[cnt] = 1;
            fa[cnt] = f;
            ch[f][val[f] < x] = cnt;
            ch[cnt][1] = ch[cnt][0] = 0;
            update(f);
            splay(cnt);
            break;
        }
    }
}

int find(int x) {     //查询 排名=有多少比他小的 + 1
    int now = rt, res = 0;
    while(1) {
        if(x < val[now]) now = ch[now][0]; //左
        else {
            if(ch[now][0]) res += sz[ch[now][0]];
            if(x == val[now]) {
                splay(now);
                return res + 1;
            }
            res += cn[now];
            now = ch[now][1];
        }
    }
}

int ffind(int x) {  //查询排名为x的数
    int now = rt, res = 0;
    while(1) {
        if(ch[now][0] && x <= res + sz[ch[now][0]]) now = ch[now][0];
        else {
            if(ch[now][0]) res += sz[ch[now][0]];
            res += cn[now];

            if(res >= x) return val[now];
            now = ch[now][1];
        }
    }
}

int pre() {  //前驱
    int now = ch[rt][0];
    while(ch[now][1]) now = ch[now][1];
    return now;
}

int nex() {
    int now = ch[rt][1];
    while(ch[now][0]) now = ch[now][0];
    return now;
}

void del(int x) {
    int no = find(x);
    if(cn[rt] > 1) {
        cn[rt]--;
        return;
    }

    if(!ch[rt][0] && !ch[rt][1]) {  //没孩子
        clear(rt);
        rt = 0;
        return;
    }
    if(!ch[rt][0]) {
        int oldrt = rt;
        rt = ch[rt][1]; fa[rt] = 0;
        clear(oldrt);
        return;
    }

    if(!ch[rt][1]) {
        int oldrt = rt;
        rt = ch[rt][0]; fa[rt] = 0;
        clear(oldrt);
        return;
    }
    // two children
    int lrt = pre();
    int oldrt = rt;
    splay(lrt);
    fa[ch[oldrt][1]] = lrt;
    ch[rt][1] = ch[oldrt][1];
    clear(oldrt);
    update(rt);
}

int main() {
    rt = 0;
    cnt = 0;
    int T;
    scanf("%d", &T);
    while(T--) {
        int opt, x;
        scanf("%d%d", &opt, &x);
        switch(opt) {
            case 1: inser(x); break;
            case 2: del(x); break;
            case 3: printf("%d\n", find(x)); break;
            case 4: printf("%d\n", ffind(x)); break;
            case 5: inser(x), printf("%d\n", val[pre()]), del(x); break;
            case 6: inser(x), printf("%d\n", val[nex()]), del(x); break;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lwqq3/p/11261567.html

时间: 2024-10-16 15:06:33

P3369 【模板】普通平衡树 (splay)的相关文章

【BZOJ3224】Tyvj 1728 普通平衡树 Splay

Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大的数)6. 求x的后继(后继定义为大于x,且最小的数) Input 第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6) Output 对于操作3,4,5,6每行输

luoguP3369[模板]普通平衡树(Treap/SBT) 题解

链接一下题目:luoguP3369[模板]普通平衡树(Treap/SBT) #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<ctime> #include<queue> #incl

洛谷 P3391 【模板】文艺平衡树(Splay)

题目背景 这是一道经典的Splay模板题--文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是 (1,2,?n?1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,r] 数据保证 1≤l≤r≤n 输出格式: 输出一行n个数字,表示原始序列经过m次变换后的结果

bzoj3224 普通平衡树(splay 模板)

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 11427  Solved: 4878[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为

【转】 史上最详尽的平衡树(splay)讲解与模板(非指针版spaly)

ORZ原创Clove学姐: 变量声明:f[i]表示i的父结点,ch[i][0]表示i的左儿子,ch[i][1]表示i的右儿子,key[i]表示i的关键字(即结点i代表的那个数字),cnt[i]表示i结点的关键字出现的次数(相当于权值),size[i]表示包括i的这个子树的大小:sz为整棵树的大小,root为整棵树的根. 再介绍几个基本操作: [clear操作]:将当前点的各项值都清0(用于删除之后) inline void clear(int x){ ch[x][0]=ch[x][1]=f[x]

bzoj3224 普通平衡树 splay模板

题目传送门 题目大意:完成一颗splay树. 思路:模板题,学着还是很有意思的. 学习splay树:蒟蒻yyb 该题模板:汪立超 #include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; int root,N=0,n,p,q; int fa[100001],c[100001][2],size[100001],sp[100001]; void

[P3369]普通平衡树(Splay版)

模板,不解释 #include<bits/stdc++.h> using namespace std; const int mxn=1e5+5; int fa[mxn],ch[mxn][2],sz[mxn],cnt[mxn],val[mxn],rt,tot; namespace Splay { void push_up(int x) { sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x]; }; void rotate(int x) { int y=fa[x],z=f

[bzoj3223]文艺平衡树(splay区间反转模板)

解题关键:splay模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; const int N = 100005; int ch[N][2],par[N],val[N],cnt[

平衡树Splay模板

1 //cooode by xiaolang 2 #include<cstdio> 3 #include<iostream> 4 #define N 100010 5 using namespace std; 6 int fa[N],ch[N][2],siz[N],cnt[N],data[N],root,nn,n,tot; 7 8 void pushup(int rt) { 9 int l=ch[rt][0],r=ch[rt][1]; 10 siz[rt]=siz[l]+siz[r