纯板子。。。。

题意:

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

然后。。。

然后就没有然后了。。。。

注意rotate。。。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cctype>
using namespace std;
#define olinr return
#define love_nmr 0
#define INF 0x7ffffffa
#define mod 123123
int n;
int cnt;
int root;
int siz[mod];
int dat[mod];
int fat[mod];
int num[mod];
int son[mod][];
inline int read()
{
int f=,x=;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
f=-f;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
olinr x*f;
}
inline void put(int x)
{
if(x<)
{
putchar('-');
x=-x;
}
if(x>)
put(x/);
putchar(x%+'');
} /* ------------------------olinr love nmr--------------------------------*/ inline void update(int x)
{
siz[x]=siz[son[x][]]+siz[son[x][]]+num[x];
}
inline void rotate(int x,int &o)
{
int y=fat[x];
int z=fat[y];
bool xx=son[y][]==x;
bool yy=xx^;
if(y==o)
o=x;
else
son[z][son[z][]==y]=x;
fat[x]=z;
fat[y]=x;
fat[son[x][yy]]=y;
son[y][xx]=son[x][yy];
son[x][yy]=y;
update(y);
update(x);
olinr;
}
inline void splay(int x,int &o)
{
while(x!=o)
{
int y=fat[x];
int z=fat[y];
if(y!=o)
{
if((son[y][]==x)^(son[z][]==y))
rotate(x,o);
else
rotate(y,o);
}
rotate(x,o);
}
}
inline int x_rank_n(int x)
{
int now=root;
int rank=;
while(+love_nmr)
{
if(x<dat[now])
now=son[now][];
else
{
rank+=siz[son[now][]];
if(x==dat[now])
{
splay(now,root);
olinr rank+;
}
rank+=num[now];
now=son[now][];
}
}
}
inline int n_rank_x(int x)
{
int now=root;
while(+love_nmr)
{
if(siz[son[now][]]>=x)
now=son[now][];
else
{
if(num[now]+siz[son[now][]]>=x)
olinr dat[now];
x-=(num[now]+siz[son[now][]]);
now=son[now][];
}
}
}
inline int pre(int x)
{
x_rank_n(x);
int now=son[root][];
while(son[now][])
now=son[now][];
olinr now;
}
inline int nxt(int x)
{
x_rank_n(x);
int now=son[root][];
while(son[now][])
now=son[now][];
olinr now;
}
inline int del(int x)
{
int l=pre(x);
int r=nxt(x);
splay(l,root);
splay(r,son[root][]);
int now=son[son[root][]][];
siz[now]--;
num[now]--;
if(!num[now])
{
son[fat[now]][]=;
fat[now]=;
}
splay(son[root][],root);
}
inline void insert(int x)
{
if(!root)
{
root=++cnt;
siz[root]=;
dat[root]=x;
num[root]=;
olinr;
}
int fa=;
int now=root;
while(+love_nmr)
{
if(dat[now]==x)
{
num[now]++;
siz[now]++;
splay(now,root);
olinr;
}
fa=now;
now=son[now][x>dat[now]];
if(!now)
{
now=++cnt;
fat[now]=fa;
son[fa][x>dat[fa]]=now;
num[now]++;
siz[now]++;
dat[now]=x;
splay(now,root);
olinr;
}
}
}
int main()
{
n=read();
int flag,x;
insert(INF);
insert(-INF);
for(int i=;i<=n;i++)
{
flag=read();
x=read();
if(flag==) insert(x);
if(flag==) del(x);
if(flag==){put(x_rank_n(x)-);putchar('\n');}
if(flag==){put(n_rank_x(x+));putchar('\n');}
if(flag==){insert(x);put(dat[pre(x)]);putchar('\n');del(x);}
if(flag==){insert(x);put(dat[nxt(x)]);putchar('\n');del(x);}
}
olinr love_nmr;
}

注释QAQ

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cctype>
using namespace std;
#define R register
#define IL inline
#define INF 2147483640
#define mod 125125
#define II int
II root; //根的编号
II n; //n个操作
II cnt; //编号
II fa[mod]; //fa[i]代表i的父亲
II son[mod][]; //son[i][0]代表i的左儿子,son[i][1]代表i的右儿子
II data[mod]; //data[i]代表树上编号为i的点的值
II size[mod]; //size[i]表示以i为根的子树的sum的和 (大小) (包括自己)
II sum[mod]; //sum[i]表示数字i的个数
IL II read() //快读(有负数)
{
R II x=,f=;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
f=-f;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return x*f;
}
IL void update(R II x) //更新x
{
size[x]=size[son[x][]]+size[son[x][]]+sum[x];
//当前点的size == 左儿子的size + 右儿子的size + 当前点的个数
}
IL void rotate(R II x,R II &o) //旋转
{
R II y=fa[x]; //y为x的父亲
R II z=fa[y]; //z为y的父亲,z为x的爷爷
R bool xx=(son[y][]==x); //xx表示y的右儿子是否为x
R bool yy=xx^; //yy表示y的左儿子是否为x
if(y==o) //x的父亲y是旋转的目标点
o=x; //目标点变为x
else //x的父亲y不是旋转的目标点
son[z][son [z][]==y]=x; //如果z的右儿子是y,那么现在z的右儿子是x;如果z的右儿子不是y,那么现在z的左儿子是x
fa[x]=z; //x的父亲是z
fa[y]=x; //y的父亲是x(x转了上去)
fa[son[x][yy]]=y; //如果原来y的左儿子是x,那么现在x的右儿子是y;如果原来y的右儿子是x,那么现在x的左儿子是y
son[y][xx]=son[x][yy]; //原来x的(右||左)儿子变成了先在y的(左||右)儿子
son[x][yy]=y; //如果原来y的(左||右)儿子是x,那么现在x的(右||左)儿子是y
update(y); //维护y
update(x); //维护x
}
IL void splay(R II x,R II &o)
{
while(x!=o) //只要为转到目标节点
{
R II y=fa[x]; //y是x的父亲
R II z=fa[y]; //z是y的父亲,x的爷爷
if(y!=o) //如果y不是目标节点
{
if((son[y][]==x)^(son[z][]==y)) //如果xyz不在一条直链上
rotate(x,o); //x朝o的方向转
else //在一条直链上
rotate(y,o); //转y
}
rotate(x,o); //转x
}
}
IL void insert(R II x)
{
if(!root) //是根
{ //初始化
root=++cnt;
data[root]=x;
size[root]=;
sum[root]=;
return;
}
R II now=root; //从根开始找合适位置
R II fat=; //now的father
while()
{
if(data[now]==x) //树中已有该元素
{
sum[now]++; //累计数量
splay(now,root); //转
return;
}
fat=now;
now=son[now][data[now]<x]; //now往孩子上跳
if(!now) //跳到了叶子的孩子(还没有)
{
now=++cnt; //初始化
fa[now]=fat;
son[fat][data[fat]<x]=now;
size[now]++;
sum[now]++;
data[now]=x;
splay(now,root);
return;
}
}
}
IL II x_rank_n(R II x) //找树中的数x的排名
{
R II rank=;
R II now=root; //从根往下找
while()
{
if(x<data[now]) //小于当前点往左跳
now=son[now][];
else
{
rank+=size[son[now][]];//排名加上左子树大小(x一定比左子树所有值都大,不然就会往左跳)
if(x==data[now]) //找到了x
{
splay(now,root); //转上去
return rank+; //x的位置
}
rank+=sum[now]; //往右跳说明它比前面所有数都大,所以要累计前面数的个数
now=son[now][]; //累计完后在往后跳
}
}
}
IL II rank_n_x(R II x)
{
R II rank=;
R II now=root;
while()
{
if(size[son[now][]]>=x) //目标在左子树
now=son[now][]; //往左跳
else
{
if(sum[now]+size[son[now][]]>=x) //now就是x的位置
return data[now];
x-=(sum[now]+size[son[now][]]); //x减左边个数
now=son[now][]; //再向右跳
}
}
}
IL II pre(R II x)
{
x_rank_n(x);
R II now=son[root][];
while(son[now][])
now=son[now][];
return now;
}
IL II nxt(R II x)
{
x_rank_n(x);
R II now=son[root][];
while(son[now][])
now=son[now][];
return now;
}
IL void del(R II x)
{
R II l=pre(x);
R II r=nxt(x);
splay(l,root);
splay(r,son[root][]);
R II now=son[son[root][]][];
sum[now]--;
size[now]--;
if(!sum[now])
{
son[fa[now]][]=;
fa[now]=;
}
splay(son[root][],root);
}
int main()
{
ios::sync_with_stdio(false);
n=read();
insert(-INF);
insert(INF);
for(R II i=;i<=n;i++)
{
R II x=read();
R II y=read();
if(x==) insert(y);
if(x==) del(y);
if(x==) printf("%d\n",x_rank_n(y)-);
if(x==) printf("%d\n",rank_n_x(y+));
if(x==) insert(y),printf("%d\n",data[pre(y)]),del(y);
if(x==) insert(y),printf("%d\n",data[nxt(y)]),del(y);
}
return ;
}

P3369 【模板】普通平衡树的更多相关文章

  1. luoguP3391[模板]文艺平衡树(Splay) 题解

    链接一下题目:luoguP3391[模板]文艺平衡树(Splay) 平衡树解析 这里的Splay维护的显然不再是权值排序 现在按照的是序列中的编号排序(不过在这道题目里面就是权值诶...) 那么,继续 ...

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

    链接一下题目:luoguP3369[模板]普通平衡树(Treap/SBT) 平衡树解析 #include<iostream> #include<cstdlib> #includ ...

  3. 【洛谷P3369】 (模板)普通平衡树

    https://www.luogu.org/problemnew/show/P3369 Splay模板 #include<iostream> #include<cstdio> ...

  4. [luogu3369/bzoj3224]普通平衡树(splay模板、平衡树初探)

    解题关键:splay模板题整理. 如何不加入极大极小值?(待思考) #include<cstdio> #include<cstring> #include<algorit ...

  5. 【模板】平衡树——Treap和Splay

    二叉搜索树($BST$):一棵带权二叉树,满足左子树的权值均小于根节点的权值,右子树的权值均大于根节点的权值.且左右子树也分别是二叉搜索树.(如下) $BST$的作用:维护一个有序数列,支持插入$x$ ...

  6. 【洛谷P3369】普通平衡树——Splay学习笔记(一)

    二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...

  7. 洛谷.3369.[模板]普通平衡树(Splay)

    题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...

  8. 洛谷.3369.[模板]普通平衡树(fhq Treap)

    题目链接 第一次(2017.12.24): #include<cstdio> #include<cctype> #include<algorithm> //#def ...

  9. 洛谷.3391.[模板]文艺平衡树(Splay)

    题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...

  10. 文艺平衡Splay树学习笔记(2)

    本blog会讲一些简单的Splay的应用,包括但不局限于 1. Splay 维护数组下标,支持区间reserve操作,解决区间问题 2. Splay 的启发式合并(按元素多少合并) 3. 线段树+Sp ...

随机推荐

  1. Java_异常_05_ OutOfMemoryError: Java heap space

    一.异常现象: 二.异常原因 JAVA的堆栈设置太小 注: 出现此异常之后,会引发其他的问题. 三.异常解决 手动设置Heap size: 修改 TOMCAT_HOME/bin/catalina.sh ...

  2. Java_异常_03_ java.lang.NoClassDefFoundError: org/apache/commons/pool/KeyedObjectPoolFactory

    异常信息: java.lang.NoClassDefFoundError: org/apache/commons/pool/KeyedObjectPoolFactory 原因: 我用的是commons ...

  3. python实现无序列表:链表

    介绍链表前我们先了解下什么是列表. 在对基本数据结构的讨论中,我们使用 Python 列表来实现所呈现的抽象数据类型.列表是一个强大但简单的收集机制,为程序员提供了各种各样的操作.然而,不是所有的编程 ...

  4. Convolutional Neural Networks for Visual Recognition 4

    Modeling one neuron 下面我们开始介绍神经网络,我们先从最简单的一个神经元的情况开始,一个简单的神经元包括输入,激励函数以及输出.如下图所示: 一个神经元类似一个线性分类器,如果激励 ...

  5. 九省联考2018 D1T1 一双木棋

    Alice和Bob轮流在n*m的棋盘上放棋子 a[i][j]表示Alice放在这的收益,b[i][j]表示Bob放在这的收益 一个地方没有棋子且它的左边上边都有棋子才能放棋子,边界外视为有一圈棋子 n ...

  6. bzoj 1070 修车 —— 费用流

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1070 需要考虑前面修的车对后面等待的车造成的时间增加: 其实可以从每个人修车的顺序考虑,如果 ...

  7. Linux使用tcpdump抓取网络数据包示例

    tcpdump是Linux命令行下常用的的一个抓包工具,记录一下平时常用的方式,测试机器系统是ubuntu 12.04. tcpdump的命令格式 tcpdump的参数众多,通过man tcpdump ...

  8. 对API的理解

    一. API(Application Programming Interface,应用程序编程接口) 1)定义:API是远程服务器或者操作系统的一些函数,是它们的一部分: 2)功能:用来接收应用程序( ...

  9. 差一点搞混了Transactional注解

    今天给我的Srping业务层加如下Service和Transactional注解: @Service @Scope(BeanDefinition.SCOPE_SINGLETON) @Transacti ...

  10. Mac系统的launchd、守护进程daemon(2013笔记整理)

    1. launchd Mac系统下通用的进程管理器,是Mac系统下非常重要的一个进程,一般来说该进程不允许直接以命令行的形式调用.只能通过其控制管理界面,launchctl来进行控制. launchd ...