(转)关于treap的板子理解
关于treap的板子理解:
关于结构体的定义:(一般平衡树无法理解的变量名):
v:节点的值;
size:子节点的个数(包括自己);
cnt:相同的值的副本数;
l:左儿子;
r:右儿子;
右旋:
父亲变成左儿子,左儿子变成父亲的右儿子;
void zig(int x)
{
int h=s[x].l;
s[x].l=s[x].r;s[h].r=x;
s[h].size=s[x].size;
up(x);
x=h;
return ;
}
左旋:
就是右旋相反就变成左旋;
void zag(int x)
{
int h=s[x].r;
s[x].r=s[x].l;s[h].l=x;
s[h].size=s[x].size;
up(x);
x=h;
}
插入:
1.insert函数有两个函数,x和k;
这里k取地址会比较方便;
k就是目前节点,开始时就是根节点rt;
2.如果目前节点为0,即为上一个传过来的是0,那么这个值之前没有过,所以新建一个节点,就是
s[k].size=s[k].cnt=;
s[k].ran=rand();
s[k].v=x;
return ;
3.如果这个值之前出现过,那么副本cnt++;
众所周知s[k].l总是小于k,s[k].r总是大于k;
所以见代码
void insert(int x,int &k)
{
if(!k)
{
s[k].size=s[k].cnt=;
s[k].ran=rand();
s[k].v=x;
return ;
}
s[k].size++;
if(s[k].v==x) s[k].cnt++;
if(x>s[k].v)
{
insert(x,s[k].r);
if(s[s[k].l].ran<s[k].ran)zig(k);
}
else if(x<s[k].v)
{
insert(x,s[k].l);
if(s[s[k].l].ran<s[k].ran)zag(k);
}
return ;
}
删除节点:
1.如果就没有这个节点,就直接return;
2.如果这个节点就是这个值,并且这个点的副本>1, tr[k].cnt--;tr[k].size--;
3.如果左节点和右节点只有一个有值,这个点就是他的那个子节点(删除这个点之后就是他的子节点当这个点);
4.他的左儿子虚拟值(平衡树根据这个虚拟值可以提高效率)小于右儿子的虚拟值,那么右旋
5.else 左旋;
inline void del(int x,int &k)
{
if(!k) return ;
if(tr[k].v==x)
{
if(tr[k].cnt>)
{
tr[k].cnt--;
tr[k].size--;
}
else if(tr[k].l*tr[k].r==) k=tr[k].l+tr[k].r;
else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd) zig(k),del(x,k);
else zag(k),del(x,k);
return ;
}
tr[k].size--;
if(tr[k].v>x) del(x,tr[k].l);
else del(x,tr[k].r);
return ;
}
询问排名:
1.如果k==0,那么就return 0
2.如果这个值就是目前的节点的值,那么返回他的左儿子+1;(注意要加1,左儿子的是小于我的,所以+1,就是我的排名);
3.如果目前节点的值大于要查的值就递归他的左子树;
4.否则递归右子树;
inline int qrnk(int x,int k)
{
if(!k) return ;
if(tr[k].v==x) return tr[tr[k].l].size+;
else if(tr[k].v>x) return qrnk(x,tr[k].l);
else return qrnk(x,tr[k].r)+tr[tr[k].l].size+tr[k].cnt;
}
询问排名是x的值;
1.如果没有这个值,就return 0;
2.如果这个排名小于左子树的子树点的值并且排名小于左子树的子树点加上他的副本数的点;
那么就 return tr[k].v;
3.如果要查的值小于等于左子树的儿子值return qnum(x,tr[k].l);;
4.否则递归右子树;
inline int qnum(int x,int k)
{
if(!k) return ;
if(x>tr[tr[k].l].size&&x<=tr[tr[k].l].size+tr[k].cnt) return tr[k].v;
else if(x<=tr[tr[k].l].size) return qnum(x,tr[k].l);
else return qnum(x-tr[tr[k].l].size-tr[k].cnt,tr[k].r);
}
询问前驱:
1.如果没有就return -inf;
2.如果小于这个点的值递归左子树;
否则返回 max(tr[k].v,qpre(x,tr[k].r));
询问后继:
1.(在这里偷懒一下)就是和询问前驱相反的;
inline int qnxt(int x,int k)
{
if(!k) return inf;
if(x>=tr[k].v) return qnxt(x,tr[k].r);
else return min(tr[k].v,qnxt(x,tr[k].l));
}
平衡树的主要作用就是:
- 插入 x 数;
- 删除 x 数(若有多个相同的数,因只删除一个);
- 查询 x 数的排名(若有多个相同的数,因输出最小的排名);
- 查询排名为 x 的数;
- 求 x 的前趋(前趋定义为小于 x ,且最大的数);
- 求 x 的后继(后继定义为大于 x ,且最小的数)。
有一道题叫普通平衡树;适合刚学平衡树的童鞋;
完整代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
using namespace std;
const int inf=0x7fffffff;
int n,rt;
int tot=;
struct node{
int v,cnt,l,r,rnd,size;
}tr[];
inline void up(int k)
{
tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].cnt;
}
inline void zig(int &k)
{
int h=tr[k].l;
tr[k].l=tr[h].r,tr[h].r=k;
tr[h].size=tr[k].size;
up(k);
k=h;
return ;
}
inline void zag(int &k)
{
int h=tr[k].r;
tr[k].r=tr[h].l,tr[h].l=k;
tr[h].size=tr[k].size;
up(k);
k=h;
return ;
}
inline void insert(int x,int &k){
if(!k){
k=++tot;
tr[k].v=x;
tr[k].cnt=tr[k].size=;
tr[k].rnd=rand();
return ;
}
tr[k].size++;
if(x==tr[k].v) tr[k].cnt++;
else if(x<tr[k].v)
{
insert(x,tr[k].l);
if(tr[tr[k].l].rnd<tr[k].rnd) zig(k);
}
else if(x>tr[k].v)
{
insert(x,tr[k].r);
if(tr[tr[k].r].rnd<tr[k].rnd) zag(k);
}
return ;
}
inline void del(int x,int &k)
{
if(!k) return ;
if(tr[k].v==x)
{
if(tr[k].cnt>)
{
tr[k].cnt--;
tr[k].size--;
}
else if(tr[k].l*tr[k].r==) k=tr[k].l+tr[k].r;
else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd) zig(k),del(x,k);
else zag(k),del(x,k);
return ;
}
tr[k].size--;
if(tr[k].v>x) del(x,tr[k].l);
else del(x,tr[k].r);
return ;
}
inline int qrnk(int x,int k)
{
if(!k) return ;
if(tr[k].v==x) return tr[tr[k].l].size+;
else if(tr[k].v>x) return qrnk(x,tr[k].l);
else return qrnk(x,tr[k].r)+tr[tr[k].l].size+tr[k].cnt;
}
inline int qnum(int x,int k)
{
if(!k) return ;
if(x>tr[tr[k].l].size&&x<=tr[tr[k].l].size+tr[k].cnt) return tr[k].v;
else if(x<=tr[tr[k].l].size) return qnum(x,tr[k].l);
else return qnum(x-tr[tr[k].l].size-tr[k].cnt,tr[k].r);
}
inline int qpre(int x,int k)
{
if(!k) return -inf;
if(x<=tr[k].v) return qpre(x,tr[k].l);
else return max(tr[k].v,qpre(x,tr[k].r));
}
inline int qnxt(int x,int k)
{
if(!k) return inf;
if(x>=tr[k].v) return qnxt(x,tr[k].r);
else return min(tr[k].v,qnxt(x,tr[k].l));
}
int main()
{
srand(time());
scanf("%d",&n);
for(int i=;i<=n;i++)
{
int f,x;
scanf("%d%d",&f,&x);
if(f==) insert(x,rt);
if(f==) del(x,rt);
if(f==) printf("%d\n",qrnk(x,rt));
if(f==) printf("%d\n",qnum(x,rt));
if(f==) printf("%d\n",qpre(x,rt));
if(f==) printf("%d\n",qnxt(x,rt));
}
return ;
}
蒟蒻理解,如有错误以其他大佬的为主
作者:lsc
(转)关于treap的板子理解的更多相关文章
- Treap 模板
感觉平衡树也没有以前想的那么玄乎,(其实set超好用的),非旋式Treap挺好理解,和可并堆,二叉搜索树有很大联系 推荐博客:http://memphis.is-programmer.com/post ...
- bzoj 3224: Tyvj 1728 普通平衡树【非旋treap】
就是非旋treap的板子 #include<iostream> #include<cstdio> #include<cstdlib> using namespace ...
- 浅谈无旋treap(fhq_treap)
一.简介 无旋Treap(fhq_treap),是一种不用旋转的treap,其代码复杂度不高,应用范围广(能代替普通treap和splay的所有功能),是一种极其强大的平衡树. 无旋Treap是一个叫 ...
- P3369 【模板】普通平衡树(splay)
P3369 [模板]普通平衡树 就是不用treap splay板子,好好背吧TAT #include<iostream> #include<cstdio> #include&l ...
- P4008 [NOI2003]文本编辑器
思路 FHQ Treap的板子 用FHQ Treap维护中序遍历序列即可 然后数组开够! 代码 #include <cstdio> #include <cstring> #in ...
- [日常] HEOI 2019 退役记
HEOI 2019 退役记 先开坑 坐等AFO 啥时候想起来就更一点(咕咕咕) Day 0 早上打了个LCT, 打完一遍过编译一遍AC...(看来不考这玩意了) 然后进行了一些精神文明建设活动奶了一口 ...
- THUWC2019爆零记
Day -1 现在在机房里,准备敲敲板子什么的. 今天晚上放假诶,要好好睡一下.好好睡是不可能的,这辈子不可能的. Day 0 现在在酒店,\(lwh\)神仙在超越,我打了个\(treap\)的板子就 ...
- THUSC2017 游记
你若安好,便是晴天. Day 0 中午就要出发了,上午浮躁的不行,根本写不下题去. 到了火车站之后发现教练和lyc和ztc在4车靠近5车的那一边,然而我在5车靠近4车的那边,尴尬…… 本来是想着上了火 ...
- 50 days before NOI2017
2017.5.31 今天开了这个博客,打算每天来写点东西,嗯...毕竟要NOI了嘛... 第一天跑到常州里集训,打开题目一看湖南集训题... T1刷一下写完,然后交了然后发现错了...赶紧改过来,大概 ...
随机推荐
- 学习记录:《高性能javascript》【持续更新】
在看这本书的时候,遇到不懂得地方我一般都会百度一下.这里记录一下我在这本书里捡到的杂碎知识: 1.arrayObject.shift() 2.concat() 3.绑定监听的事件的方法(兼容IE,Fi ...
- 【旧文章搬运】Windbg+Vmware驱动调试入门(四)---VirtualKD内核调试加速工具
原文发表于百度空间,2009-01-09========================================================================== 今天又想起 ...
- 图片加水印文字,logo。生成缩略图
简单JSP代码 图片加水银文字 try { String path = request.getRealPath("images\\01.jpg"); out.print(path) ...
- B. Spider Man
time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...
- linux下svn的建库以及相关配置
1.安装svn软件 yum install subversion -y 2.建立库的根目录,此目录下为所有库的根目录(路径为:/home/svn-server/) ,然后进入此目录 mkdir /ho ...
- Codeforces 快速竞技#4
快速竞技#4 A–Duff and Meat588A = =这题不知道怎么写题解了.. 直接上code---. #include<bits/stdc++.h> #include<st ...
- Ecliplse 指定JRE
http://blog.csdn.net/hongweigg/article/details/9987649 在Eclipse启动的过程中,它会去找系统环境变量设置的JRE_HOME或JDK_HOME ...
- 洛谷P2515 [HAOI2010]软件安装(tarjan缩点+树形dp)
传送门 我们可以把每一个$d$看做它的父亲,这样这个东西就构成了一个树形结构 问题是他有可能形成环,所以我们还需要一遍tarjan缩点 缩完点后从0向所有入度为零的点连边 然后再跑一下树形dp就行了 ...
- MVC和MTV结构分析
@font-face { font-family: "Times New Roman"; }@font-face { font-family: "宋体"; }@ ...
- $.ajax从后台取数据 然后做字符串拼接的例子