Treap 模板 poj1442&hdu4557
原理可以看hihocoder上面的讲解,很清楚,不多说了。
模板抄lrj训练指南上面的。
/**
Treap 实现 名次树
功能: 1.找到排名为k的元素
2.值为x的元素的名次 初始化:Node* root = NULL;
*/
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std; struct Node {
Node * ch[]; // 0左子树 1右子树
int r; // 随机优先级
int v; // 值
int s; // 以s为根的子树的大小
Node(int v):v(v)
{
ch[] = ch[] = NULL;
r = rand();
s = ;
}
bool operator<(const Node& rhs) const { // 按随机优先级排序
return r < rhs.r;
}
int cmp(int x) const
{
if (x == v) return -;
return x < v ? : ;
}
void maintain() // 更新
{
s = ;
if (ch[] != NULL) s += ch[]->s;
if (ch[] != NULL) s += ch[]->s;
}
} ; void rotate(Node* &o, int d) // d=0 代表左转, d=1代表右转
{
Node* k = o->ch[d^];
o->ch[d^] = k->ch[d];
k->ch[d] = o;
o->maintain();
k->maintain();
o = k;
} void insert(Node* &o, int x) // o是根 x是插入的值
{
if (o == NULL) {
o = new Node(x);
} else {
int d = (x < o->v ? : ); // 不用cmp函数因为可能有重复的值
insert(o->ch[d], x);
if ((o->ch[d]->r) > (o->r)) rotate(o, d^);
}
o->maintain();
} void remove(Node* &o, int x)
{
int d = o->cmp(x);
if (d == -) {
Node* u = o;
if (o->ch[] != NULL && o->ch[] != NULL) {
int d2 = ((o->ch[]->r) > (o->ch[]->r) ? : );
rotate(o, d2);
remove(o->ch[d2], x);
} else {
if (o->ch[] == NULL) o = o->ch[];
else o = o->ch[];
delete u;
}
} else {
remove(o->ch[d], x);
}
if (o != NULL) o->maintain();
} int find(Node* o, int x) // 因为remove和insert都没有查值存不存在 记得操作之前调用find
{
while (o != NULL) {
int d = o->cmp(x);
if (d == -) return ;
else o = o->ch[d];
}
return ;
} int kth(Node* &o, int k, int fg) // fg=1第k大的值 fg=0第k小的值 返回0表示没找到
{
if (o == NULL || k <= || k > o->s) return ;
int s = (o->ch[fg] == NULL ? : o->ch[fg]->s);
if (k == s+) return o->v;
else if (k <= s) return kth(o->ch[fg], k, fg);
else return kth(o->ch[fg^], k-s-, fg);
} int prv(Node* &o, int x) // 查找x前面的元素 (<x的最大值
{
if (o == NULL) return -;
if (x <= o->v) return prv(o->ch[], x);
int ans = prv(o->ch[], x); return ans == - ? o->v : ans;
} int nxt(Node* &o, int x) // 查找x后面的元素 (>x的最大值
{
if (o == NULL) return -;
if (x >= o->v) return nxt(o->ch[], x);
int ans = nxt(o->ch[], x);
return ans == - ? o->v : ans;
} void mergeto(Node* &src, Node* &dest) // 合并两棵树 把src加到dest上 src和dest都是树的根
{
if (src->ch[] != NULL) mergeto(src->ch[], dest);
if (src->ch[] != NULL) mergeto(src->ch[], dest);
insert(dest, src->v);
delete src;
src = NULL;
} void print(Node* &o)
{
if (o == NULL) return ;
print(o->ch[]);
printf("%d ", o->v);
print(o->ch[]);
} int main()
{
Node* root = NULL;
insert(root, );
insert(root, );
insert(root, );
insert(root, );
remove(root, );
print(root);
return ;
}
例题:
上面hihocoder的例题,这个代码是照着讲解自己写的
//Treap.cpp #include <stdio.h>
#include <string.h>
#include <stdlib.h> const int N = ; struct Treap {
int father, left, right;
int key, weight;
void init(int k, int w, int fa) {
left = right = -;
father = fa, key = k, weight = w;
}
} tp[N];
int root;
int treap_cnt; int new_treap(int k, int w, int fa = -)
{
tp[treap_cnt].init(k, w, fa);
return treap_cnt++;
} void left_rotate(int a) // 左旋 把节点A的右儿子节点B转到A的父亲节点
{
int b = tp[a].right;
tp[b].father = tp[a].father;
if (tp[tp[a].father].left == a) { // 判断a是父节点的左儿子还是右儿子 并用b替换
tp[tp[a].father].left = b;
} else {
tp[tp[a].father].right = b;
}
tp[a].right = tp[b].left;
if (tp[b].left != -) tp[tp[b].left].father = a;
tp[b].left = a;
tp[a].father = b;
} void right_rotate(int a) // 右旋 把节点A的左儿子节点B转到A的父亲节点
{
int b = tp[a].left;
tp[b].father = tp[a].father;
if (tp[tp[a].father].left == a) tp[tp[a].father].left = b;
else tp[tp[a].father].right = b;
tp[a].left = tp[b].right;
if (tp[b].right != -) tp[tp[b].right].father = a;
tp[b].right = a;
tp[a].father = b;
} int insert(int a, int key)
{
if (key < tp[a].key) {
if (tp[a].left == -) {
tp[a].left = new_treap(key, rand(), a);
return tp[a].left;
} else {
return insert(tp[a].left, key);
}
} else {
if (tp[a].right == -) {
tp[a].right = new_treap(key, rand(), a);
return tp[a].right;
} else {
return insert(tp[a].right, key);
}
}
} void rotate(int a) // 维持小顶堆
{
int fa = tp[a].father;
while (fa != -) {
if (tp[a].weight < tp[fa].weight) {
if (a == tp[fa].left) right_rotate(fa);
else left_rotate(fa);
fa = tp[a].father;
} else {
break;
}
}
if (fa == -) root = a;
} int find(int a, int key)
{
int cur = a, pre = -;
while (cur != -) {
if (tp[cur].key > key) {
pre = cur;
cur = tp[cur].left;
} else if (tp[cur].key < key) {
pre = cur;
cur = tp[cur].right;
} else {
return key;
}
}
while (pre != -) {
if (tp[pre].key < key) return tp[pre].key;
pre = tp[pre].father;
}
return -;
} void print(int a)
{
if (a == -) return;
print(tp[a].left);
printf("%d(%d) ", a, tp[a].key);
print(tp[a].right);
} int main(int argc, char const *argv[])
{
//freopen("in", "r", stdin);
root = -;
treap_cnt = ;
int n;
char op[];
int k;
scanf("%d", &n);
while (n--) {
scanf("%s%d", op, &k);
if (*op == 'I') {
if (root == -) root = new_treap(k, rand());
else rotate(insert(root, k));
} else {
printf("%d\n", find(root, k));
}
}
return ;
}
poj1442,直接套模板,比较简单
/**
Treap 实现 名次树
功能: 1.找到排名为k的元素
2.值为x的元素的名次
*/
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std; struct Node {
Node * ch[]; // 0左子树 1右子树
int r; // 随机优先级
int v; // 值
int s; // 以s为根的子树的大小
Node(int v):v(v)
{
ch[] = ch[] = NULL;
r = rand();
s = ;
}
bool operator<(const Node& rhs) const { // 按随机优先级排序
return r < rhs.r;
}
int cmp(int x) const
{
if (x == v) return -;
return x < v ? : ;
}
void maintain() // 更新
{
s = ;
if (ch[] != NULL) s += ch[]->s;
if (ch[] != NULL) s += ch[]->s;
}
} ; void rotate(Node* &o, int d) // d=0 代表左转, d=1代表右转
{
Node* k = o->ch[d^];
o->ch[d^] = k->ch[d];
k->ch[d] = o;
o->maintain();
k->maintain();
o = k;
} void insert(Node* &o, int x) // o是根 x是插入的值
{
if (o == NULL) {
o = new Node(x);
} else {
int d = (x < o->v ? : ); // 不用cmp函数因为可能有重复的值
insert(o->ch[d], x);
if ((o->ch[d]->r) > (o->r)) rotate(o, d^);
}
o->maintain();
} void remove(Node* &o, int x)
{
int d = o->cmp(x);
if (d == -) {
Node* u = o;
if (o->ch[] != NULL && o->ch[] != NULL) {
int d2 = ((o->ch[]->r) > (o->ch[]->r) ? : );
rotate(o, d2);
remove(o->ch[d2], x);
} else {
if (o->ch[] == NULL) o = o->ch[];
else o = o->ch[];
delete u;
}
} else {
remove(o->ch[d], x);
}
if (o != NULL) o->maintain();
} int find(Node* &o, int x) // 因为remove和insert都没有查值存不存在 记得操作之前调用find
{
while (o != NULL) {
int d = o->cmp(x);
if (d == -) return ; // exist
else o = o->ch[d];
}
return ; // not exist
} int kth(Node* &o, int k, int fg) // fg=1第k大的值 fg=0第k小的值 返回0表示没找到
{
if (o == NULL || k <= || k > o->s) return ;
int s = (o->ch[fg] == NULL ? : o->ch[fg]->s);
if (k == s+) return o->v;
else if (k <= s) return kth(o->ch[fg], k, fg);
else return kth(o->ch[fg^], k-s-, fg);
} void mergeto(Node* &src, Node* &dest)
{
if (src->ch[] != NULL) mergeto(src->ch[], dest);
if (src->ch[] != NULL) mergeto(src->ch[], dest);
insert(dest, src->v);
delete src;
src = NULL;
} const int N = ;
int a[N];
int main()
{
//freopen("in", "r", stdin);
int m, n;
while (~scanf("%d%d", &m, &n)) {
Node* root = NULL;
for (int i = ; i <= m; ++i) {
scanf("%d", a+i);
}
int x = , u, cnt = ;
for (int i = ; i < n; ++i) {
scanf("%d", &u);
while (cnt < u) {
insert(root, a[++cnt]);
}
printf("%d\n", kth(root, ++x, ));
}
}
return ;
}
hdu4557
每个结点加了一个元素t,排序查找都要考虑t
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
using namespace std; struct Node {
Node * ch[]; // 0左子树 1右子树
int r; // 随机优先级
int v; // 值
int t;
int s; // 以s为根的子树的大小
Node(int v, int t):v(v), t(t)
{
ch[] = ch[] = NULL;
r = rand();
s = ;
}
bool operator<(const Node& rhs) const { // 按随机优先级排序
if (r == rhs.r) return t < rhs.t;
return r < rhs.r;
}
int cmp(int x, int y) const
{
if (x == v && y == t) return -;
if (x == v) return y < t ? : ;
return x < v ? : ;
}
void maintain() // 更新
{
s = ;
if (ch[] != NULL) s += ch[]->s;
if (ch[] != NULL) s += ch[]->s;
}
} ; void rotate(Node* &o, int d) // d=0 代表左转, d=1代表右转
{
Node* k = o->ch[d^];
o->ch[d^] = k->ch[d];
k->ch[d] = o;
o->maintain();
k->maintain();
o = k;
} void insert(Node* &o, int x, int y) // o是根 x是插入的值
{
if (o == NULL) {
o = new Node(x, y);
} else {
int d = o->cmp(x, y);
insert(o->ch[d], x, y);
if ((o->ch[d]->r) > (o->r)) rotate(o, d^);
}
o->maintain();
} void remove(Node* &o, int x, int y)
{
int d = o->cmp(x, y);
if (d == -) {
Node* u = o;
if (o->ch[] != NULL && o->ch[] != NULL) {
int d2 = ((o->ch[]->r) > (o->ch[]->r) ? : );
rotate(o, d2);
remove(o->ch[d2], x, y);
} else {
if (o->ch[] == NULL) o = o->ch[];
else o = o->ch[];
delete u;
}
} else {
remove(o->ch[d], x, y);
}
if (o != NULL) o->maintain();
} int nxt(Node* &o, int x, int &res) // 查找x后面的元素 (>=x的最小值
{
if (o == NULL) return -;
if (o->v < x) return nxt(o->ch[], x, res);
res = o->v;
int ans = nxt(o->ch[], x, res);
return ans == - ? o->t : ans;
} void print(Node* &o)
{
if (o == NULL) return ;
print(o->ch[]);
printf("%d ", o->v);
print(o->ch[]);
} int main()
{
freopen("in", "r", stdin);
int T;
cin >> T;
int cas = ;
while (T--) {
printf("Case #%d:\n", ++cas);
int n;
cin >> n;
char op[];
string name;
int abi, res;
Node* root = NULL;
map<int, string> mp;
for (int i = ; i < n; ++i) {
scanf("%s", op);
if (*op == 'A') {
cin >> name;
scanf("%d", &abi);
mp[i] = name;
insert(root, abi, i);
printf("%d\n", root->s);
} else {
scanf("%d", &abi);
int ans = nxt(root, abi, res);
if (ans == -) printf("WAIT...\n");
else {
cout << mp[ans] << endl;
remove(root, res, ans);
}
}//printf("debug:"); print(root); printf("\n");
}
}
}
Treap 模板 poj1442&hdu4557的更多相关文章
- BZOJ 1588: Treap 模板
1588: [HNOI2002]营业额统计 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 12171 Solved: 4352 Description ...
- [luogu3369]普通平衡树(treap模板)
解题关键:treap模板保存. #include<cstdio> #include<cstring> #include<algorithm> #include< ...
- 平衡树Treap模板与原理
这次我们来讲一讲Treap(splay以后再更) 平衡树是一种排序二叉树(或二叉搜索树),所以排序二叉树可以迅速地判断两个值的大小,当然操作肯定不止那么多(不然我们还学什么). 而平衡树在排序二叉树的 ...
- POJ1442-查询第K大-Treap模板题
模板题,以后要学splay,大概看一下treap就好了. #include <cstdio> #include <algorithm> #include <cstring ...
- Treap 模板
感觉平衡树也没有以前想的那么玄乎,(其实set超好用的),非旋式Treap挺好理解,和可并堆,二叉搜索树有很大联系 推荐博客:http://memphis.is-programmer.com/post ...
- 【Treap模板详细注释】BZOJ3224-普通平衡树
模板题:D错因见注释 #include<iostream> #include<cstdio> #include<cstring> #include<algor ...
- 非旋treap模板
bzoj3580 非旋转treap 在大神教导下发现split一段区间时先split右边再split左边比较好写 #include <cstdio> #include <cstdli ...
- codevs 4543 treap 模板
type rec=record lc,rc,v,rnd,size,w,fa:longint; end; var n,root,tot,ans,opt,x,i,po:longint; tr:array[ ...
- Treap模板
平衡树总是有用的,set由于过度封装没有办法实现找比x小的元素有多少个,这就显得很不方便了,所以封装了个Treap,万一以后用的着呢- -01 #pragma warning(disable:4996 ...
随机推荐
- swift苹果的下一代语言
http://numbbbbb.github.io/the-swift-programming-language-in-chinese/chapter1/01_swift.html 有时间再看,bas ...
- 接口和JAVA设计模式
- PreparedStatement是如何大幅度提高性能的
本文讲述了如何正确的使用prepared statements.为什么它可以让你的应用程序运行的更快,和同样的让数据库操作变的更快. 为什么Prepared Statements非常重要?如何正确的 ...
- Mac中编译安装Qt 4.4
解压下载到的.gz源码:gunzip xxx.tar.gztar xvf xxx.tar, 其实在Mac中可以直接双击解压的.然后定位到解压后的目录下:./configuremakesudo make ...
- ARMv7 .n和.w指令宽度指示符后缀
Thumb code里,.n后缀强迫生成16bit的代码,即Thumb code,若是在arm code里用.n会报错,若是机器指令没有办法用16表示也会报错 Thumb code里,.w后缀强迫生成 ...
- cdev[典]
linux-2.6.22/include/linux/cdev.hstruct cdev { struct kobject kobj; // 每个 cdev 都是一个 kobje ...
- Git教程(6)常用技巧之远程分支简单示例
基础 1,"master" 与"origin" “master” 是当你运行 git init 时默认的起始分支名字,原因仅仅是它的广泛使用,“origin” ...
- linux 用grep匹配横线
file的内容如下: ADSFADSFSDFASDFJKJK----------------------------------------ADSFADSFSDFASDFJKJK----------- ...
- Java开发之多线程下载和断点续传
代码实现了多线程下载和断点续传功能 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...
- BZOJ1954: Pku3764 The xor-longest Path
题解: 在树上i到j的异或和可以直接转化为i到根的异或和^j到根的异或和. 所以我们把每个点到根的异或和处理出来放到trie里面,再把每个点放进去跑一遍即可. 代码: #include<cstd ...