关于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));
}

平衡树的主要作用就是:

  1. 插入 x  数;
  2. 删除 x  数(若有多个相同的数,因只删除一个);
  3. 查询 x  数的排名(若有多个相同的数,因输出最小的排名);
  4. 查询排名为  x  的数;
  5. 求  x  的前趋(前趋定义为小于  x ,且最大的数);
  6. 求  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的板子理解的更多相关文章

  1. Treap 模板

    感觉平衡树也没有以前想的那么玄乎,(其实set超好用的),非旋式Treap挺好理解,和可并堆,二叉搜索树有很大联系 推荐博客:http://memphis.is-programmer.com/post ...

  2. bzoj 3224: Tyvj 1728 普通平衡树【非旋treap】

    就是非旋treap的板子 #include<iostream> #include<cstdio> #include<cstdlib> using namespace ...

  3. 浅谈无旋treap(fhq_treap)

    一.简介 无旋Treap(fhq_treap),是一种不用旋转的treap,其代码复杂度不高,应用范围广(能代替普通treap和splay的所有功能),是一种极其强大的平衡树. 无旋Treap是一个叫 ...

  4. P3369 【模板】普通平衡树(splay)

    P3369 [模板]普通平衡树 就是不用treap splay板子,好好背吧TAT #include<iostream> #include<cstdio> #include&l ...

  5. P4008 [NOI2003]文本编辑器

    思路 FHQ Treap的板子 用FHQ Treap维护中序遍历序列即可 然后数组开够! 代码 #include <cstdio> #include <cstring> #in ...

  6. [日常] HEOI 2019 退役记

    HEOI 2019 退役记 先开坑 坐等AFO 啥时候想起来就更一点(咕咕咕) Day 0 早上打了个LCT, 打完一遍过编译一遍AC...(看来不考这玩意了) 然后进行了一些精神文明建设活动奶了一口 ...

  7. THUWC2019爆零记

    Day -1 现在在机房里,准备敲敲板子什么的. 今天晚上放假诶,要好好睡一下.好好睡是不可能的,这辈子不可能的. Day 0 现在在酒店,\(lwh\)神仙在超越,我打了个\(treap\)的板子就 ...

  8. THUSC2017 游记

    你若安好,便是晴天. Day 0 中午就要出发了,上午浮躁的不行,根本写不下题去. 到了火车站之后发现教练和lyc和ztc在4车靠近5车的那一边,然而我在5车靠近4车的那边,尴尬…… 本来是想着上了火 ...

  9. 50 days before NOI2017

    2017.5.31 今天开了这个博客,打算每天来写点东西,嗯...毕竟要NOI了嘛... 第一天跑到常州里集训,打开题目一看湖南集训题... T1刷一下写完,然后交了然后发现错了...赶紧改过来,大概 ...

随机推荐

  1. angularJS ng-if的用法

    ng-if主要是用来判断是否显示,也可以做为而者选择其中一个的方法,满足判断条件ng-if="变量名" 显示,否者不显示,也可以用ng-if="!变量名"取反, ...

  2. Java中断机制

    1. 引言 当我们点击某个杀毒软件的取消按钮来停止查杀病毒时,当我们在控制台敲入quit命令以结束某个后台服务时……都需要通过一个线程去取消另一个线程正在执行的任务.Java没有提供一种安全直接的方法 ...

  3. Java throw与throws

    以前虽然知道一些异常的处理,也用过一些,但是对throw和throws区别还是有不太清楚.今天用实例测试一下. 异常处理机制 异常处理是对可能出现的异常进行处理,以防止程序遇到异常时被卡死,处于一直等 ...

  4. .NETFramework:HttpContext

    ylbtech-.NETFramework:HttpContext 1.返回顶部 1. #region 程序集 System.Web, Version=4.0.0.0, Culture=neutral ...

  5. 安装Nginx作为文件服务器

    我是在Windows上安装的,在Linux上也一样 #Windows server2008 R2 #Nginx1.12 Nginx安装包下载地址:http://nginx.org/en/downloa ...

  6. ORACLE PL/SQL 实例精解之第七章 迭代控制之二

    7.1CONTINUE语句 CONTINUE语句会导致循环终止当前迭代.并且当CONTINUE的条件为TRUE时,开始执行该循环的下一次迭代.需要借助于IF语句来计算COUNTINUE条件.当CONT ...

  7. Unity陀螺仪

    using UnityEngine; using System.Collections; using UnityEngine.UI; //摄像机 陀螺仪转动 public class TGyro : ...

  8. bzoj 2555: SubString【后缀自动机+LCT】

    一直WA--找了半天错的发现居然是解密那里的mask其实是不能动的--传进去的会变,但是真实的那个不会变-- 然后就是后缀自动机,用LCT维护parent树了--注意不能makeroot,因为自动机的 ...

  9. 运行scrapyd报错

    转自:    https://blog.csdn.net/qq_29719097/article/details/89431234 web.Server Traceback (most recent ...

  10. AForge.net简介和认识

    AForge.NET是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,模糊系统,机器人控制等领域.这个框架由一系列的类库组成.主要包括有 ...