(转)关于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刷一下写完,然后交了然后发现错了...赶紧改过来,大概 ...
随机推荐
- 微信小程序在线制作 自己制作微信小程序
小程序是个什么东西?怎么自己制作微信小程序?微信小程序在线制作难吗?最近老是听这类问题,耳朵都长茧子了. 百牛信息技术bainiu.ltd整理发布于博客园 接下来作为一个技术人员的角度就为大家分析一下 ...
- nodejs URL 详解
1 我们可以使用.parse方法来将一个URL字符串转换为URL对象 例如: url.parse('http://user:pass@host.com:8080/p/a/t/h?query=strin ...
- A. Mishka and Game
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- E20180430-hm
pants n. <英>(紧身的)短裤; <美> 裤子; 喘气( pant的名词复数 ); leggings n. 绑腿; 裹腿; 绷腿; 袜统; redundant adj. ...
- html行内要素与块级要素
行内要素:在一行里,不可设置width和height,不能上下外铺(margin) span 块状要素,标准的 div
- HDU6050: Funny Function(推公式+矩阵快速幂)
传送门 题意 利用给出的式子求\(F_{m,1}\) 分析 直接推公式(都是找规律大佬) \(n为偶数,F_{m,1}=\frac{2(2^n-1)^{m-1}}3\) \(n为奇数,F_{m,1}= ...
- CodeForces 687C【DP】
题意: 给你n个数,然后让这些数相加组合,然后在这些组合的数里可以再相加组合搞出给定 k,输出这些组合的数. 思路: DP. //在枚举到第i个coin的时,dp[i][j],i 肯定能被a[i]组合 ...
- 手机测试用例-wap测试用例
Software Test Case P/F comment tester test time P/F comment tester ID 功能描述 操作步骤 预期结果 备注 wap_001 wap ...
- iOS NSUserDefaults [setValue:forKey:] [setObject:forKey:] <Objc> setValue(_,forKey:) set(_,forKey) <Swift 3>
前者其实是NSObject都可以调用的KVC方法,后者才是NSUserDefaults的实例方法: 这里参数的类型是nullable id,但是我建议你在传null的时候慎重考虑,否则你的应用就可能面 ...
- AtCoder Grand Contest 005 C - Tree Restoring
题目传送门:https://agc005.contest.atcoder.jp/tasks/agc005_c 题目大意: 给定一个长度为\(N\)的整数序列\(A_i\),问能否构造一个\(N\)个节 ...