bzoj3224 普通平衡树(splay 模板)

3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 11427  Solved: 4878
[Submit][Status][Discuss]

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每行输出一个数,表示对应答案

Sample Input

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

Sample Output

106465
84185
492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-1e7,1e7]

数据如下http://pan.baidu.com/s/1jHMJwO2

Source

平衡树

#include <cstdio>
#define Maxn 1000000
using namespace std;
int f[Maxn];//father
int ch[Maxn][2];//child ; 0 for left ; 1 for right
int key[Maxn];//key
int cnt[Maxn];//value
int siz[Maxn];//size of subtree
int sz,root;//size of tree and root
//clear the ndoe

void clear(int x)
{
    ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=siz[x]=0;
}

//rightson return 1;left son return 0
int getson(int x)
{
    return ch[f[x]][1]==x;
}

//update the size
void update(int x)
{
    siz[x]=cnt[x];
    if (ch[x][0]) siz[x]+=siz[ch[x][0]];
    if (ch[x][1]) siz[x]+=siz[ch[x][1]];
}

//retation
int rotate(int x)
{
    int fa=f[x],fafa=f[fa],k=getson(x);
    ch[fa][k]=ch[x][k^1];f[ch[fa][k]]=fa;
    ch[x][k^1]=fa;f[fa]=x;
    f[x]=fafa;
    if (fafa)
        ch[fafa][ch[fafa][1]==fa]=x;
    update(fa);update(x);
}

//rotate until x is the root
void splay(int x)
{
    for (int fa;fa=f[x];rotate(x))
        if (f[fa])
            rotate(getson(x)==getson(fa) ? fa : x);
    root=x;
}

int pre()
{
    int now=ch[root][0];
    while(ch[now][1])
        now=ch[now][1];
    return now;
}

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

//find x‘s pos
int findpos(int v)
{
    int now=root,ans=0;
    while(1)
    {
        if (v<key[now])
            now=ch[now][0];
        else
        {
            ans+=ch[now][0]?siz[ch[now][0]]:0;
            if (v==key[now])
            {
                splay(now);
                return ans+1;
            }
            ans+=cnt[now];
            now=ch[now][1];
        }
    }
}

//find pos‘s x
int findx(int x)
{
    int now=root;
    while(1)
    {
        if (ch[now][0] && x<=siz[ch[now][0]])
            now=ch[now][0];
        else
        {
            int temp=(ch[now][0]?siz[ch[now][0]]:0)+cnt[now];
            if (x<=temp)
                return key[now];
            x-=temp;
            now=ch[now][1];
        }
    }
}

//ceate a new splay node
void create(int v)
{
    sz++;
    ch[sz][0]=ch[sz][1]=f[sz]=0;
    key[sz]=v;
    cnt[sz]=1;
    siz[sz]=1;
    //root=sz;
}

//insert a node
void insert(int v)
{
    if (!root)
        create(v),root=sz;
    else
    {
        int now=root,fa=0;
        while(1)
        {
            if (key[now]==v)
            {
                cnt[now]++;
                update(now);update(fa);
                splay(now);
                break;
            }
            fa=now;
            now=ch[fa][v>key[fa]];
            if (!now)
            {
                create(v);
                f[sz]=fa;
                ch[fa][v>key[fa]]=sz;
                update(fa);
                splay(sz);
                break;
            }
        }
    }
}

void del(int x)
{
    int t=findpos(x);
    if (cnt[root]>1)
    {
        cnt[root]--;
        update(root);
        return;
    }
    //none
    if (!ch[root][0] && !ch[root][1])
    {
        clear(root);
        root=0;
        return;
    }
    //one
    if (!ch[root][1])
    {
        int temp=root;
        root=ch[root][0];
        f[root]=0;
        clear(temp);
        return;
    }
    else
    if (!ch[root][0])
    {
        int temp=root;
        root=ch[root][1];
        f[root]=0;
        clear(temp);
        return;
    }
    //two
    int pre1=pre(),temp=root;
    splay(pre1);
    f[ch[temp][1]]=root;
    ch[root][1]=ch[temp][1];
    clear(temp);
    update(root);
}

int main()
{
    int n,opt,x;
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
    {
        scanf("%d%d",&opt,&x);
        switch(opt)
        {
            case 1: insert(x); break;
            case 2: del(x); break;
            case 3: printf("%d\n",findpos(x)); break;
            case 4: printf("%d\n",findx(x)); break;
            case 5: insert(x); printf("%d\n",key[pre()]); del(x); break;
            case 6: insert(x); printf("%d\n",key[nex()]); del(x); break;
        }
    }
}
时间: 2024-08-06 08:38:18

bzoj3224 普通平衡树(splay 模板)的相关文章

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

平衡树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

【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每行输

【转】 史上最详尽的平衡树(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]

洛谷 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次变换后的结果

文艺平衡树(splay模板)

题干:splay模板,要求维护区间反转. splay是一种码量小于treap,但支持排名,前驱后继等treap可求的东西,也支持区间反转的平衡树. 但是有两个坏处: 1.splay常数远远大于treap以及stl中的set. 2.没有可持久化splay,但有可持久化treap. 下面是代码: 1.pushup以及pushdown pushup用于维护某点所在子树大小. void pushup(int u) { tr[u].siz = tr[tr[u].ch[0]].siz + tr[tr[u].

[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[

bzoj1500(妥妥的splay模板题)

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 6366  Solved: 1910 [Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次

splay模板

先贴一份不怎么完善的模板,等刷一些题目熟悉之后再来完善.代码参考自kuangbin及cxlove两位大神. splay的基本功能 题目:维护一个数列,支持以下几种操作: 1. 插入:在当前数列第posi 个数字后面插入tot 个数字:若在数列首位插入,则posi 为0. 2. 删除:从当前数列第posi 个数字开始连续删除tot 个数字. 3. 修改:从当前数列第posi 个数字开始连续tot 个数字统一修改为c . 4. 翻转:取出从当前数列第posi 个数字开始的tot 个数字,翻转后放入原