P3369 【模板】普通平衡树
纯板子。。。。
题意:
- 插入 xx 数
- 删除 xx 数(若有多个相同的数,因只删除一个)
- 查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 。若有多个相同的数,因输出最小的排名)
- 查询排名为 xx 的数
- 求 xx 的前驱(前驱定义为小于 xx ,且最大的数)
- 求 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 【模板】普通平衡树的更多相关文章
- luoguP3391[模板]文艺平衡树(Splay) 题解
链接一下题目:luoguP3391[模板]文艺平衡树(Splay) 平衡树解析 这里的Splay维护的显然不再是权值排序 现在按照的是序列中的编号排序(不过在这道题目里面就是权值诶...) 那么,继续 ...
- luoguP3369[模板]普通平衡树(Treap/SBT) 题解
链接一下题目:luoguP3369[模板]普通平衡树(Treap/SBT) 平衡树解析 #include<iostream> #include<cstdlib> #includ ...
- 【洛谷P3369】 (模板)普通平衡树
https://www.luogu.org/problemnew/show/P3369 Splay模板 #include<iostream> #include<cstdio> ...
- [luogu3369/bzoj3224]普通平衡树(splay模板、平衡树初探)
解题关键:splay模板题整理. 如何不加入极大极小值?(待思考) #include<cstdio> #include<cstring> #include<algorit ...
- 【模板】平衡树——Treap和Splay
二叉搜索树($BST$):一棵带权二叉树,满足左子树的权值均小于根节点的权值,右子树的权值均大于根节点的权值.且左右子树也分别是二叉搜索树.(如下) $BST$的作用:维护一个有序数列,支持插入$x$ ...
- 【洛谷P3369】普通平衡树——Splay学习笔记(一)
二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...
- 洛谷.3369.[模板]普通平衡树(Splay)
题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...
- 洛谷.3369.[模板]普通平衡树(fhq Treap)
题目链接 第一次(2017.12.24): #include<cstdio> #include<cctype> #include<algorithm> //#def ...
- 洛谷.3391.[模板]文艺平衡树(Splay)
题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...
- 文艺平衡Splay树学习笔记(2)
本blog会讲一些简单的Splay的应用,包括但不局限于 1. Splay 维护数组下标,支持区间reserve操作,解决区间问题 2. Splay 的启发式合并(按元素多少合并) 3. 线段树+Sp ...
随机推荐
- JavaUtil_08_StringUtil_commons-lang3 之 StringUtils
二.参考资料 1.[commons]字符串工具类——commons-lang3之StringUtils
- C++中的前置和后置++
在C++中进行操作符重载的时候,前置++返回的是一个引用. 这就设计到了对于基本变量进行前置操作时候的理解了. 例如,对于int类型变量,在进行前置++的时候,是会将i进行加1,然后返回i的引用.而i ...
- Arc066_E Addition and Subtraction Hard
传送门 题目大意 给定一个加减法的表达式,让你任意的添加合法的括号对,使的表达式最大. 题解 考虑到任意左括号一定加在减号右边,那么对于第一个左括号,与该左括号相邻的只含有加号的子序列的贡献一定为负, ...
- CodeForces - 1019D(BZOJ3707圈地):Large Triangle (几何,找面积为S的三角形)
题意:给定平面上N个点,问是否存在三角形,其面积为S. 思路:选择Y轴,枚举这个Y轴,面积大小只与|y-Y|有关,然后二分,具体的可以先去做BZOJ3707. 具体的: 1,先对点排序,X坐标为第一关 ...
- POJ1422 Air Raid 和 CH6902 Vani和Cl2捉迷藏
Air Raid Language:Default Air Raid Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9547 A ...
- CQOI2018做题记录
T1.破解D-H协议 传送门 这个题就是BSGS的板子题-- 然后这里补充一点嘛,就是第二重循环的枚举范围.我们是在枚举\(a^{tm-y}\),把tm换成i,这个的最大值就是\(i - (m - 1 ...
- Winform程序实现多显示屏、多屏幕显示的2种方法
这篇文章主要介绍了Winform窗口实现多显示屏显示的2种方法,本文直接给出了实现代码,并对其中的一些重要参数做了解释,需要的朋友可以参考下. 一台主机连接了2台显示器(2个显卡),要求一个程序的两个 ...
- asp.net C#操作存储过程读取存储过程输出参数值
这段时间在做一个价格平台的项目时候,同事让我写一个存储过程.该存储过程是根据查询条件得出一组新数据,并且返回该组数据的总条数,此处的存储过程我用到了分页,其中主要知识点和难点是之前做项目的时候没有用到 ...
- 给.sh文件添加可执行权限
有时我们运行.sh文件时会发现没有权限,具体解决方案如下 第一种:bash+执行文件 第二种:chmod命令 如果给所有人添加可执行权限:chmod a+x 文件名:如果给文件所有者添加可执行权限:c ...
- Python:删除字符串中的字符
一.删除字符串两端的一种或多种字符 #strip().lstrip().rstrip()方法:(默认删除空格符) A.list.strip(字符):删除字符串两端的一种或多种字符: #例:删除字符串s ...