洛谷 P3369 【模板】普通平衡树 (Treap)
题目链接:P3369 【模板】普通平衡树
题意
构造一种数据结构满足给出的 6 种操作。
思路
平衡树
平衡树的模板题。
先学习了一下 Treap。
Treap 在插入结点时给该结点随机生成一个额外的权值,然后用该权值维护一个大根堆,如果某个结点不满足大根堆的性质,就通过旋转与父节点交换。
对于删除某个结点,通过不断向下旋转直至变成叶子结点,然后直接删除即可。
模板来自《算法竞赛进阶指南》。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
struct Treap {
int l, r;
int val, dat;
int cnt, size;
} a[maxn];
int tot, root;
int n;
int new_node(int val) {
a[++tot].val = val;
a[tot].dat = rand();
a[tot].cnt = a[tot].size = 1;
return tot;
}
void update(int p) {
a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;
}
void build() {
new_node(-inf), new_node(inf);
root = 1, a[1].r = 2;
update(root);
}
int get_rank(int p, int val) {
if (p == 0) return 0;
if (val == a[p].val) return a[a[p].l].size + 1;
if (val < a[p].val) return get_rank(a[p].l, val);
return get_rank(a[p].r, val) + a[a[p].l].size + a[p].cnt;
}
int get_val(int p, int rank) {
if (p == 0) return inf;
if (a[a[p].l].size >= rank) return get_val(a[p].l, rank);
if (a[a[p].l].size + a[p].cnt >= rank) return a[p].val;
return get_val(a[p].r, rank - a[a[p].l].size - a[p].cnt);
}
// 右旋
void zig(int &p) {
int q = a[p].l;
a[p].l = a[q].r, a[q].r = p, p = q;
update(a[p].r), update(p);
}
// 左旋
void zag(int &p) {
int q = a[p].r;
a[p].r = a[q].l, a[q].l = p, p = q;
update(a[p].l), update(p);
}
void add(int &p, int val) {
if (p == 0) {
p = new_node(val);
return;
}
if (val == a[p].val) {
a[p].cnt++;
} else if (val < a[p].val) {
add(a[p].l, val);
if (a[p].dat < a[a[p].l].dat) zig(p);
} else {
add(a[p].r, val);
if (a[p].dat < a[a[p].r].dat) zag(p);
}
update(p);
}
int get_pre(int val) {
int ans = 1; // a[1].val==-inf
int p = root;
while (p) {
if (val == a[p].val) {
if (a[p].l > 0) {
p = a[p].l;
while (a[p].r > 0) p = a[p].r;
ans = p;
}
break;
}
if (a[p].val < val && a[p].val > a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return a[ans].val;
}
int get_next(int val) {
int ans = 2; // a[2].val==inf
int p = root;
while (p) {
if (val == a[p].val) {
if (a[p].r > 0) {
p = a[p].r;
while (a[p].l > 0) p = a[p].l;
ans = p;
}
break;
}
if (a[p].val > val && a[p].val < a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return a[ans].val;
}
// 把非叶子结点旋转至叶子结点后直接删除
void remove(int &p, int val) {
if (p == 0) return;
if (val == a[p].val) {
if (a[p].cnt > 1) {
a[p].cnt--, update(p);
return;
}
if (a[p].l || a[p].r) { // 不是叶子节点,向下旋转
if (a[p].r == 0 || a[a[p].l].dat > a[a[p].r].dat)
zig(p), remove(a[p].r, val);
else
zag(p), remove(a[p].l, val);
update(p);
}
else p = 0; // 叶子节点,删除
return;
}
val < a[p].val ? remove(a[p].l, val) : remove(a[p].r, val);
update(p);
}
int main() {
build();
cin >> n;
while (n--) {
int op, x;
cin >> op >> x;
if(op == 1) {
add(root, x);
} else if(op == 2) {
remove(root, x);
} else if(op == 3) {
cout << get_rank(root, x) - 1 << endl;
} else if(op == 4) {
cout << get_val(root, x + 1) << endl;
} else if(op == 5) {
cout << get_pre(x) << endl;
} else {
cout << get_next(x) << endl;
}
}
return 0;
}
洛谷 P3369 【模板】普通平衡树 (Treap)的更多相关文章
- 洛谷.3369.[模板]普通平衡树(fhq Treap)
题目链接 第一次(2017.12.24): #include<cstdio> #include<cctype> #include<algorithm> //#def ...
- 【洛谷P3369】普通平衡树——Splay学习笔记(一)
二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...
- 洛谷.3369.[模板]普通平衡树(Splay)
题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...
- 洛谷.3391.[模板]文艺平衡树(Splay)
题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...
- 洛谷P3369 【模板】普通平衡树(Treap/SBT)
洛谷P3369 [模板]普通平衡树(Treap/SBT) 平衡树,一种其妙的数据结构 题目传送门 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除 ...
- 【洛谷P3369】【模板】普通平衡树题解
[洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...
- 洛谷P3369普通平衡树(Treap)
题目传送门 转载自https://www.cnblogs.com/fengzhiyuan/articles/7994428.html,转载请注明出处 Treap 简介 Treap 是一种二叉查找树.它 ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- luoguP3369[模板]普通平衡树(Treap/SBT) 题解
链接一下题目:luoguP3369[模板]普通平衡树(Treap/SBT) 平衡树解析 #include<iostream> #include<cstdlib> #includ ...
- 绝对是全网最好的Splay 入门详解——洛谷P3369&BZOJ3224: Tyvj 1728 普通平衡树 包教包会
平衡树是什么东西想必我就不用说太多了吧. 百度百科: 一个月之前的某天晚上,yuli巨佬为我们初步讲解了Splay,当时接触到了平衡树里的旋转等各种骚操作,感觉非常厉害.而第二天我调Splay的模板竟 ...
随机推荐
- WebBrowser常用浏览操作
WebBrowser1.GoHome; //到浏览器默认主页 WebBrowser1.Refresh; //刷新 WebBrowser1.GoBack; //后退 WebBrowser1.GoForw ...
- The request with exception: The SSL connection could not be established, see inner exception. requestId 解决方案
DOTNET CORE 部署 Centos7 抛出异常 环境变量如下: .NET Core SDK (reflecting any global.json): Version: 2.2.401 Com ...
- 修改maven包本地默认位置
前言 这段时间上岸了,就有时间整理电脑的资料(强迫症重度患者),就向maven以及gradle的仓库位置动手了. 目的 改变maven的默认位置 步骤 修改maven的配置文件setting.xml( ...
- CF1220F
CF1220F 把整棵树分成1的左边和1的右边两部分 最优情况两边子树深度的差一定可以是一 如果还可以是2,也可以通过把多的那一边的点往另一边移使他变成1 如果往一个端点加点,一定不会使这一边变优,也 ...
- CTU OPEN 2017 Pond Cascade /// 思维
题目大意: 给定N F 给定N个水池的大小 每个水池都以流量F开始注水 当位置较前的水池注满后 水会溢出到下一个水池 求 最后一个水池开始溢出的时间 和 所有水池全部注满的时间 1.最后一个n水池开始 ...
- Linux下svn更新含有中文名称的库无法更新问题
Linux下更新含有中文名称的库文件时,出现如下提示: SVN Error: Can't convert string from native encoding to 'UTF-8' 通过google ...
- Puppeteer自动化测试cnode.js中文社区
如果完全不了解puppeteer的朋友可以去看看我的这篇随笔:https://www.cnblogs.com/zlforever-young/p/11569890.html 开始之前需要了解的知识:E ...
- 2018-2-13-win10-uwp-网络编程
title author date CreateTime categories win10 uwp 网络编程 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17: ...
- SecureCRT无法删除和退格的解决办法
一 选项中,设置自动保存 二 选项=>会话选项 选择linux终端.然后在映射键中,选择delete 等映射信息
- Bash: Removing leading zeroes from a variable
old=" # sed removes leading zeroes from stdin new=$(echo $old | sed 's/^0*//')