不得不说平衡树博大精深,除了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. matlab 求已知概率密度函数的随机数生成

    N=10000; %需要随机数的个数 a=zeros(N,1); %存放随机数的数列 n=0; f1=@(t) 1./(1.2*pi*(1+5*(t-7.3).^2)); f2=@(t) 1./(1. ...

  2. The linux command 之引用

    [me@linuxbox ~]$ echo this is a test this is a test shell 会对echo进行单词分割(word splitting)去除多余的空白. [me@l ...

  3. WifiManager Wifi 管理器&&知识点

    WifiManager 主要使用的技术: SimpleWifi,MahaApp.Metro控件 一 网卡设置 1.获取所有网卡(NetWorkAdapter类) 方法A 通过API SELECT * ...

  4. kubernetes istio的快速安装和使用例子

    安装 [root@master ~]# wget https://github.com/istio/istio/releases/download/1.1.5/istio-1.1.5-linux.ta ...

  5. 暑假集训test-8-14~8-15

    我不想写博客辣. 拖了三天的一起写,结果就是写不下去了...果然应该改一道写一道么.. 题面题解代码也懒得往博客上放了,屯U盘里了... 因为太菜还有两道没有改. 题解外的一些参考: lyc大佬的进程 ...

  6. mysql mac客户端: sequel,mysql-workbench

    sequel: https://sequelpro.com/download#auto-start mysql-workbench:https://dev.mysql.com/downloads/fi ...

  7. tomcat JAVA_OPTS设置

    原文地址:https://blog.csdn.net/bamboo_cqh/article/details/72820700 AVA_OPTS ,顾名思义,是用来设置JVM相关运行参数的变量. JVM ...

  8. day21-time与random等常用模块与包

    2018-08-05 # ********************day21-time与random等常用模块与包 ******************* # 参考资料# python模块(转自Yua ...

  9. python模块(转自Yuan先生)

    模块&包(****)                                                                模块(modue)的概念: 在计算机程序的开 ...

  10. IK分词器插件

    (1)源码 https://github.com/medcl/elasticsearch-analysis-ik  (2)releases https://github.com/medcl/elast ...