Treap树模板hdu-4585
时间:2019-09-14
本文章向大家介绍Treap树模板hdu-4585,主要包括Treap树模板hdu-4585使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
目录
例题:hdu 4585
Treap树
是一种简单的平衡二叉搜索树。
二叉搜索树的每一个节点都有一个键值,除此之外Treap树为每个节点人为添加了一个称之为优先级的权值。对于键值来说,这是一棵二叉搜索树,对于权值来说这是一个堆。
1、Treap树的唯一性
Treap树的重要特性:另每个节点的优先级互不相等,那么整棵树的形态时唯一的,和元素的插入顺序没有关系。
2、Treap树的平衡问题
树的形态依赖于节点的优先级,那么如何配置每个节点的优先级,才能避免二叉树的形态退化成链表?最简单的方法时把每个节点的优先级进行随机赋值,那么生成的Treap树形态也是随机的。这虽然不能保证每次生成的Treap树一定时平衡的,但是期望的插入、删除、查找的复杂度都是O(logn)的。
3、Treap树的数据结构
struct Node{
int size; // 以这个点为根的子树的节点的数量
int rank; // 优先级
int key; // 键值
Node *son[2]; //son[0]时左儿子,son[1]是右儿子
bool operator < (const Node &a)const {return rank < a.rank;}
int cmp(int x)const{
if(x == key) return -1;
return x < key? 0 : 1;
}
void update(){ //更新size
size = 1;
if(son[0] != NULL) size += son[0] -> size;
if(son[1] != NULL) size += son[1] -> size;
}
};
4、Treap树的插入
每读入一个新的节点,为它分配一个随机的优先级,插入到树中,在插入时动态调整树的结构,使它仍然是一棵Treap树。
把新节点插入到Treap树的过程有两步
(1)用朴素的插入方法把node按键值的大小插入到合适的子树上去。
(2)给node随机分配一个优先级,如果node的优先级违反了堆的性质,即它的优先级比父节点高,那么让node往上走,替代父节点,最后得到一个新的Treap树。
void insert(Node * &o, int x){ //插入
if(o == NULL){
o = new Node();
o -> son[0] = o -> son[1] = NULL;
o -> rank = rand();
o -> key = x;
o -> size = 1;
}
else{
int d = o -> cmp(x);
insert(o -> son[d], x);
o -> update();
if(o < o -> son[d])
rotate(o, d^1);
}
}
5、插入过程中维护堆的过程中用到的旋转
void rotate(Node * &o, int d){ // d = 0 左旋,d = 1右旋
Node *k = o -> son[d^1]; //d^1 == 1 - d
o -> son[d^1] = k -> son[d];
k -> son[d] = o;
o -> update();
k -> update();
o = k;
}
6、寻找第k大的数 O(logn)
int kth(Node* o, int k){
if(o == NULL || k <= 0 || k > o -> size)
return -1;
int s = o -> son[1] == NULL? 0: o -> son[1] -> size;
if(k == s + 1) return o -> key;
else if(k <= s) return kth(o -> son[1], k);
else return kth(o -> son[0], k - s - 1);
}
7、查询某个数的名次 O(logn)
int find(Node* o, int k){
if(o == NULL) return -1;
int d = o -> cmp(k);
if(d == -1)
return o -> son[1] == NULL? 1: o -> son[1] -> size + 1;
else if(d == 1) return find(o -> son[d], k);
else{
int tmp = find(o -> son[d], k);
if(tmp == -1) return -1;
else
return o -> son[1] == NULL? tmp + 1: tmp + 1 + o -> son[1] -> size;
}
}
8、hdu 4585 AC代码
//#include <bits/stdc++.h>
#include <iostream>
#include <stack>
#include <string>
#include <queue>
#include <stack>
#include <set>
#include <list>
#include <map>
#include <algorithm>
#include <string.h>
#include <time.h>
using namespace std;
int id[5000000 + 5];
struct Node{
int size; // 以这个点为根的子树的节点的数量
int rank; // 优先级
int key; // 键值
Node *son[2]; //son[0]时左儿子,son[1]是右儿子
bool operator < (const Node &a)const {return rank < a.rank;}
int cmp(int x)const{
if(x == key) return -1;
return x < key? 0 : 1;
}
void update(){ //更新size
size = 1;
if(son[0] != NULL) size += son[0] -> size;
if(son[1] != NULL) size += son[1] -> size;
}
};
void rotate(Node * &o, int d){ // d = 0 左旋,d = 1右旋
Node *k = o -> son[d^1]; //d^1 == 1 - d
o -> son[d^1] = k -> son[d];
k -> son[d] = o;
o -> update();
k -> update();
o = k;
}
void insert(Node * &o, int x){ //插入
if(o == NULL){
o = new Node();
o -> son[0] = o -> son[1] = NULL;
o -> rank = rand();
o -> key = x;
o -> size = 1;
}
else{
int d = o -> cmp(x);
insert(o -> son[d], x);
o -> update();
if(o < o -> son[d])
rotate(o, d^1);
}
}
int kth(Node* o, int k){
if(o == NULL || k <= 0 || k > o -> size)
return -1;
int s = o -> son[1] == NULL? 0: o -> son[1] -> size;
if(k == s + 1) return o -> key;
else if(k <= s) return kth(o -> son[1], k);
else return kth(o -> son[0], k - s - 1);
}
int find(Node* o, int k){
if(o == NULL) return -1;
int d = o -> cmp(k);
if(d == -1)
return o -> son[1] == NULL? 1: o -> son[1] -> size + 1;
else if(d == 1) return find(o -> son[d], k);
else{
int tmp = find(o -> son[d], k);
if(tmp == -1) return -1;
else
return o -> son[1] == NULL? tmp + 1: tmp + 1 + o -> son[1] -> size;
}
}
int main(){
int n;
while(~scanf("%d", &n) && n){
srand(time(NULL));
int k, g;
scanf("%d %d", &k, &g);
Node *root = new Node();
root -> son[0] = root -> son[1] = NULL;
root -> rank = rand();
root -> key = g;
root -> size = 1;
id[g] = k;
printf("%d %d\n", k, 1);
for(int i = 2; i <= n; i++){
scanf("%d %d", &k, &g);
id[g] = k;
insert(root, g);
int t = find(root, g);
int ans1, ans2, ans;
ans1 = kth(root, t - 1);
ans2 = kth(root, t + 1);
if(ans1 != -1 && ans2 != -1){
ans = ans1 - g >= g - ans2? ans2: ans1;
}
else if(ans1 == -1) ans = ans2;
else ans = ans1;
printf("%d %d\n", k, id[ans]);
}
}
return 0;
}
原文地址:https://www.cnblogs.com/lihello/p/11520750.html
- Java实现的一个编号生成器工具类——5种方法
- 【机器学习】有趣的机器学习:最简明入门指南
- 不使用反射,“一行代码”实现Web、WinForm窗体表单数据的填充、收集、清除,和到数据库的CRUD
- 海量数据处理利器之布隆过滤器
- ORM查询语言(OQL)简介--概念篇
- Discuz! 任意文件删除漏洞重现及分析
- .NET DLR 上的IronScheme 语言互操作&&IronScheme控制台输入中文的问题
- Java中Map相关的6大问题——每个开发人员都要注意
- android service 学习(下)
- 混淆漏洞CVE-2017-0213技术分析
- android service 学习(上)
- 黑帽SEO剖析之隐身篇
- Java中如何判断一个字符串是Java代码还是英文呢?
- 将复杂查询写到SQL配置文件--SOD框架的SQL-MAP技术简介
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java String 理解
- python遍历文件夹os.path与pathlib
- python中的yield和return
- python 类
- python 调用c语言详解
- Spring Boot 整合TkMybatis
- 数据可视化|二维统计直方图和三维统计分布图
- zetadiv: 计算zeta多样性
- Springboot笔记~filter
- 【Kubernetes】10分钟部署一套K8S集群(kubeadm)
- 【Kubernetes】给K8S部署一套UI界面
- Flutter图片添加水印功能,Flutter保存Widget为图片
- Qt音视频开发3-vlc录像存储
- 被我用烂的DEBUG调试技巧,专治各种搜索不到的问题!
- 如何用R绘制双y轴柱状图