不得不说平衡树博大精深,除了Treap,还有splay,非旋Treap和可持久化数据结构,今天先讲讲Treap,也很感谢这位大佬的博客给予我帮助:http://www.360doc.com/content/19/0120/11/5315_810146183.shtml

Treap的核心就是Tree+Heap,即在二叉搜索树的基础上根据随机数生成的优先级使树保持堆的性质,从而实现使Treap的深度不会太大的效果

核心操作就是旋转:人工YY一下……发现旋转有左旋(Zag)和右旋(Zig)两种操作,旋转时连三条边,即原顶点和新儿子的边,新定点作为原顶点父亲的边,以及上一级父亲连向新顶点的边。顶点和儿子连接的边先处理,用&p始终维护顶点坐标,因为传入的是son[father[p]],所以p变化时它父亲的儿子会自动变化,所以通过取址可以自动连边 (rotate下一层的p是上一层的son,p变上一层son就变) (详见代码)

除了insert和delete操作中需要rotate(delete要把删除点转到叶子结点再删去,insert在插入后要旋转以维护heap的性质,不要忘记操作之后要push_up),其它的代码都和二叉搜索树一样

模板题:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=;
const int N=;
const int inf=(int)2e9;
int R=; int ran()
{
static ll seed=;
seed=seed*%mod;
return (int)seed;
} struct node
{
int rnd,val,sz,ch[],num;
node(){}
node(int val,int sz,int num):val(val),sz(sz),num(num){
rnd=ran();//大根堆
ch[]=ch[]=;//和上方函数不能同时使用,若去掉该句会MLE
}
}a[];
int sum_node=;//同一节点内的相同数字的个数 void push_up(int x)
{
a[x].sz=a[x].num+a[a[x].ch[]].sz+a[a[x].ch[]].sz;
} void rotate(int &p,int d)//0:Zag 1:Zig
{
int k=a[p].ch[d^];
a[p].ch[d^]=a[k].ch[d];
a[k].ch[d]=p;
push_up(p);
push_up(k);
p=k;//传入的是son[father],father连边自动变
} void insert(int &p,int x)
{
if(!p)
{
p=++sum_node;
node tmp(x,,);
a[p]=tmp;
return;
}
if(a[p].val==x)
{
a[p].num++;
a[p].sz++;
return;
}
int d=(int)(x>a[p].val);
insert(a[p].ch[d],x);
if(a[p].rnd<a[a[p].ch[d]].rnd) rotate(p,d^);//大根堆
//本一级rotate传入的p就是上一级insert传入的son
push_up(p);
return;
} void del(int &p,int x)
{
if(!p) return;
if(a[p].val>x) del(a[p].ch[],x);
else if(a[p].val<x) del(a[p].ch[],x);
else
{
if(!a[p].ch[]&&!a[p].ch[])
{
a[p].num--; a[p].sz--;
if(a[p].num==) p=;
}
else if(a[p].ch[]&&!a[p].ch[])
{
rotate(p,);
del(a[p].ch[],x);
}
else if(!a[p].ch[]&&a[p].ch[])
{
rotate(p,);
del(a[p].ch[],x);//之前写反了
}
else
{
int d=(int)(a[a[p].ch[]].rnd>a[a[p].ch[]].rnd);
rotate(p,d);
del(a[p].ch[d],x);
}
}
push_up(p);
} int rnk(int p,int x)//以p为根的x的rank
{
if(p==) return ;//important
if(x>a[p].val)
{
return a[a[p].ch[]].sz+a[p].num+rnk(a[p].ch[],x);
}
else if(x<a[p].val)
{
return rnk(a[p].ch[],x);
}
else
{
return a[a[p].ch[]].sz+;
}
} int find(int p,int x)//已知rank查数
{
if(!p) return ;
if(a[a[p].ch[]].sz+a[p].num<x)//important(num)
{
return find(a[p].ch[],x-a[a[p].ch[]].sz-a[p].num);
}
else if(a[a[p].ch[]].sz>=x)//>=!!!
{
return find(a[p].ch[],x);
}
else
{
return a[p].val;
}
} int pre(int p,int x)
{
if(!p) return -inf;
if(a[p].val>=x)
{
return pre(a[p].ch[],x);
}
else return max(a[p].val,pre(a[p].ch[],x));
} int suc(int p,int x)
{
if(!p) return inf;
if(a[p].val<=x)
{
return suc(a[p].ch[],x);
}
else return min(a[p].val,suc(a[p].ch[],x));
} int n;
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
int opt,x;
scanf("%d%d",&opt,&x);
if(opt==) insert(R,x);//R每次会随着p改变
else if(opt==) del(R,x);
else if(opt==) printf("%d\n",rnk(R,x));
else if(opt==) printf("%d\n",find(R,x));
else if(opt==) printf("%d\n",pre(R,x));
else printf("%d\n",suc(R,x));
}
return ;
}

模板——Treap的更多相关文章

  1. [模板] Treap

    插入x 删除x 查询排名为x的数 查询x的排名 求x的前驱.后继 //Stay foolish,stay hungry,stay young,stay simple #include<iostr ...

  2. 模板—treap

    #include<iostream> #include<cstdio> #include<cstdlib> #define INF 0x7fffffff using ...

  3. 模板——Treap实现名次树

    Treap 是一种通过赋予结点随机权值的一种满足堆性质的二叉搜索树,它很好的解决了二叉搜索树顺序插入组成链式的局限性. 名次树是指在treap的每个结点中添加附加域size,表示以它为根的子树的总结点 ...

  4. LG3369 普通平衡树

    题意 维护一些数,其中需要提供以下操作: 1.插入\(x\) 2.删除\(x\)(若有多个相同的数,只删除一个) 3.查询\(x\)的排名(排名定义为比当前数小的数的个数\(+1\)) 4.查询排名为 ...

  5. treap树模板

    ///treap树模板 typedef struct Node ///节点的结构体 { Node *l,*r; int val,pri; ///节点的值和优先级 int sz; ///节点子树的节点数 ...

  6. BZOJ 3224 TYVJ 1728 普通平衡树 [Treap树模板]

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 7390  Solved: 3122 [Submit][S ...

  7. 三大平衡树(Treap + Splay + SBT)总结+模板[转]

    Treap树 核心是 利用随机数的二叉排序树的各种操作复杂度平均为O(lgn) Treap模板: #include <cstdio> #include <cstring> #i ...

  8. treap完全版模板

    这是我综合poj1442 3481 2352的treap操作 得到treap完全版模板.(经测AC) 结构体Tree { int key; //键值 int size; //该子树总节点个数 int ...

  9. Treap 模板 poj1442&hdu4557

    原理可以看hihocoder上面的讲解,很清楚,不多说了. 模板抄lrj训练指南上面的. /** Treap 实现 名次树 功能: 1.找到排名为k的元素 2.值为x的元素的名次 初始化:Node* ...

随机推荐

  1. Photoshop基础照片美化

    自从有了“ps”以后,很多事情变成了可能,你可以出现在任何你想在的地方.而最基本的美化照片的功能,我想是很多同学学习PS的初衷.当你掌握了这门技术,很多人会对你刮目相看!今天小编就和大家分享一下ps的 ...

  2. java OOP第二章_封装

    一. 封装: 属性通过private访问修饰符将其设置为私有的,只有当前类中可以访问,同时提供通过public访问修饰符的公共方法可以给任何类中访问. 通常针对属性提供公共的setter方法进行赋值, ...

  3. OC和Cocos-js的互相调用

    OC调用cocos-js #import "ScriptingCore.h" #import "cocos2d.h" #include "script ...

  4. C++之控制内存分配

    一.内存分配方式 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区.栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释 ...

  5. hive中,lateral view 与 explode函数

    hive中常规处理json数据,array类型json用get_json_object(#,"$.#")这个方法足够了,map类型复合型json就需要通过数据处理才能解析. exp ...

  6. 廖雪峰Java16函数式编程-1Lambda表达式-3方法引用

    Java8引入了Lambda表达式,可以不必编写FunctionalInterface的实现类,直接写Lambda表达式.除了Lambda表达式,我们还可以直接传入方法引用 方法引用是指:如果某个方法 ...

  7. Windows dir

    显示目录中的文件和子目录列表. DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]  [/O[[:]so ...

  8. 【转载】GPU深度发掘(一)::GPGPU数学基础教程

    作者:Dominik Göddeke                 译者:华文广 Contents 介绍 准备条件 硬件设备要求 软件设备要求 两者选择 初始化OpenGL GLUT OpenGL ...

  9. vue+Iview+gulp 生成文档说明

    1.安装npm gulp相关插件 比如:gulp.gulp-concat.gulp-htmlmin.gulp-cssmin.gulp-cheerio.gulp-clean 2. 编写gulpfile. ...

  10. fiddler设置抓取HTTPS协议数据包

    1.打开工具里的选项 2.选择弹窗中的HTTPS选项,如下图进行勾选 3.若浏览器显示不安全链接则需要添加证书 提示如下点击确定证书安装成功,可以查看安装的证书,点击Action 下图即可查看fidd ...