[模板]平衡树splay

气死我了,调了一个下午+两节课,各种大大小小的错误,各种调QAQ,最后总之是调出来了.

其实就是一个双旋操作,然后其他就是左儿子<当前节点<右儿子,剩下就是细节了.

题干:

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

    插入xxx数
    删除xxx数(若有多个相同的数,因只删除一个)
    查询xxx数的排名(排名定义为比当前数小的数的个数+1+1+1。若有多个相同的数,因输出最小的排名)
    查询排名为xxx的数
    求xxx的前驱(前驱定义为小于xxx,且最大的数)
    求xxx的后继(后继定义为大于xxx,且最小的数)

输入输出格式
输入格式:

第一行为nnn,表示操作的个数,下面nnn行每行有两个数optoptopt和xxx,optoptopt表示操作的序号( 1≤opt≤6 1 leq opt leq 6 1≤opt≤6 )

输出格式:

对于操作3,4,5,63,4,5,63,4,5,6每行输出一个数,表示对应答案

输入输出样例
输入样例#1: 复制

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

输出样例#1: 复制

106465
84185
492737

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
#define pr pair<int,int>
#define mp make_pair
const int INF = 2147480000;
const double eps = 1e-8;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
struct node
{
    int v,fa,ch[3],sum,recy;
}e[500005];
int n,points,N;
#define root e[0].ch[1]
void update(int x)
{
    e[x].sum = e[e[x].ch[0]].sum + e[e[x].ch[1]].sum + e[x].recy;
}
int iden(int x)
{
    return e[e[x].fa].ch[0] == x ? 0 : 1;
}
void connect(int x,int f,int son)
{
    e[x].fa = f;
    e[f].ch[son] = x;
}
void rotate(int x)
{
    int y = e[x].fa;
    int mroot = e[y].fa;
    int mrootson = iden(y);
    int yson = iden(x);
    int b = e[x].ch[yson ^ 1];
    connect(b,y,yson);
    connect(y,x,yson ^ 1);
    connect(x,mroot,mrootson);
    update(y);
    update(x);
}
void splay(int at,int to)
{
    to = e[to].fa;
    while(e[at].fa != to)
    {
        int up = e[at].fa;
        if(e[up].fa == to) rotate(at);
        else if(iden(up) == iden(at))
        {
            rotate(up);
            rotate(at);
        }
        else
        {
            rotate(at);
            rotate(at);
        }
    }
}
int crepoint(int v,int fa)
{
    n++;
    e[n].v = v;
    e[n].fa = fa;
    // cout<<v<<" "<<fa<<endl;
    e[n].sum = e[n].recy = 1;
    return n;
}
void destroy(int x)
{
    e[x].v = e[x].ch[0] = e[x].ch[1] = e[x].sum = e[x].fa = e[x].recy = 0;
    if(x == n)
    n--;
    while(e[n].v == 0 && e[n].sum == 0 && n > 0)
    n--;
}
int find(int v)
{
    int now = root;
    while(true)
    {
        if(e[now].v == v)
        {
            splay(now,root);
            return now;
        }
        int nxt = v < e[now].v ? 0 : 1;
        if(!e[now].ch[nxt]) return 0;
        now = e[now].ch[nxt];
    }
}
int build(int v)
{
    points++;
    // cout<<v<<endl;
    if(n == 0)
    {
        root = 1;
        crepoint(v,0);
    }
    else
    {
        int now = root;
        while(true)
        {
            // cout<<now<<endl;
            e[now].sum++;
            if(v == e[now].v)
            {
                e[now].recy++;
                return now;
            }
            int nxt = v < e[now].v ? 0 : 1;
            if(!e[now].ch[nxt])
            {
                crepoint(v,now);
                e[now].ch[nxt] = n;
                return n;
            }
            now = e[now].ch[nxt];
        }
    }
    return 0;
}
void push(int v)
{
    int add = build(v);
    if( rand() % 20 == 1 )
        splay(add,root);
}
void pop(int v)
{
    int deal = find(v);
    if(!deal) return;
    points--;
    if(e[deal].recy > 1)
    {
        e[deal].recy--;
        e[deal].sum--;
        return;
    }
    if(!e[deal].ch[0])
    {
        root = e[deal].ch[1];
        e[root].fa = 0;
    }
    else
    {
        int lef = e[deal].ch[0];
        while(e[lef].ch[1]) lef = e[lef].ch[1];
        splay(lef,e[deal].ch[0]);
        int rig = e[deal].ch[1];
        connect(rig,lef,1);connect(lef,0,1);
        update(lef);
    }
    destroy(deal);
}
int Rank(int v)
{
    int ans = 0,now = root;
    // cout<<v<<endl;
    while(true)
    {
        if(e[now].v == v)
        return ans + e[e[now].ch[0]].sum + 1;
        if(now == 0) return 0;
        if(v < e[now].v) now = e[now].ch[0];
        else
        {
            ans = ans + e[e[now].ch[0]].sum + e[now].recy;
            now = e[now].ch[1];
        }
    }
    //if(now) splay(now,root);
    return 0;
}
int atRank(int x)
{
    if(x > points) return -INF;
    int now = root;
    // cout<<root<<endl;
    while(true)
    {
        // cout<<now<<endl;
        int minused = e[now].sum - e[e[now].ch[1]].sum;
        if(x > e[e[now].ch[0]].sum && x <= minused) break;
        if(x < minused) now = e[now].ch[0];
        else
        {
            x = x - minused;
            now = e[now].ch[1];
        }
    }
    //splay(now,root);
    return e[now].v;
}
int upper(int v)
{
    int now = root;
    int result = INF;
    while(now)
    {
        if(e[now].v > v && e[now].v < result) result = e[now].v;
        if(v < e[now].v) now = e[now].ch[0];
        else
        now = e[now].ch[1];
    }
    return result;
}
int lower(int v)
{
    int now = root;
    int result = -INF;
    while(now)
    {
        // cout<<now<<endl;
        if(e[now].v < v && e[now].v > result)
        result = e[now].v;
        if(v > e[now].v) now = e[now].ch[1];
        else
        now = e[now].ch[0];
    }
    return result;
}
void Szcheck( int pos ){
    if( e[pos].ch[0] ) Szcheck(e[pos].ch[0]);
    if( e[pos].ch[1] ) Szcheck(e[pos].ch[1]);
    if( e[e[pos].ch[0]].sum + 1 + e[e[pos].ch[1]].sum != e[pos].sum ){
        cout << "Size Error At Pos" << pos << endl;
    }
}
void gg()
{
    cout<<n<<endl;
    duke(i,1,n)
    {
        printf("%d ",e[i].v);
    }
    puts("");
}
int main()
{
    // freopen("3369.in","r",stdin);
    read(N);
    duke(i,1,N)
    {
        int opt,value;
        // cout<<endl<<i<<endl;
        read(opt);read(value);
        // if(opt != 1 && opt != 2)
        // cout<<opt<<" "<<value<<endl;
        switch(opt)
        {
            case 1 : push(value);break;
            case 2 : pop(value);break;
            case 3 : cout<<Rank(value)<<endl;break;
            case 4 : {cout<<atRank(value)<<endl;}break;
            case 5 : cout<<lower(value)<<endl;break;
            case 6 : cout<<upper(value)<<endl;break;
            case 7 : gg();
        }
        //Szcheck(root);
        // cout<<i<<endl;
    }
    return 0;
}
/*
10
1 106465
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
4 1
*/

代码有点长...

原文地址:https://www.cnblogs.com/DukeLv/p/10030333.html