[Bzoj3224][Tyvj1728] 普通平衡树(splay/无旋Treap)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3224
平衡树入门题,学习学习。
splay(学习yyb巨佬)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = ;
const int INF = 1e9;
inline void read(int &n) {
register int x = , t = ;
register char ch = getchar();
while (ch != '-' && (ch<'' || ch>''))ch = getchar();
if (ch == '-') { t = -; ch = getchar(); }
while (ch >= ''&&ch <= '') { x = x * + ch - ; ch = getchar(); }
n = x * t;
}
int root, len;
struct node {
int fa;//节点的父节点
int siz;//节点的子树数量
int ch[];//节点的左(0)子节点和右(1)子节点
int val;//节点的值
int num;//节点的值的数量
}a[maxn];
inline void pushup(int x) {//更新当前节点的子树//当前子树的大小是左子树大小加上右子树大小当前当前节点个数
a[x].siz = a[a[x].ch[]].siz + a[a[x].ch[]].siz + a[x].num;
}
inline void rotate(int x) {//旋转操作//将x旋转到x的父亲的位置
int y = a[x].fa;//y是x的父节点
int z = a[y].fa;//z是x的祖父节点
int k = (a[y].ch[] == x);//求x是y的左(0)还是右(1)节点
a[z].ch[a[z].ch[] == y] = x;//求y是z的左(0)还是右(1)节点,同时将x放在该位置
a[x].fa = z;//修改x的父节点
a[y].ch[k] = a[x].ch[k ^ ];//把x的儿子给y
a[a[x].ch[k ^ ]].fa = y;//更新父节点为y
a[x].ch[k ^ ] = y;//y变为x的子节点
a[y].fa = x;//y的父亲更新为x
pushup(y), pushup(x);//更新y和x的子节点数量
}
inline void splay(int x, int goal) {//将x旋转为goal的子节点
while (a[x].fa != goal) {
int y = a[x].fa;
int z = a[y].fa;
if (z != goal)
(a[y].ch[] == x) ^ (a[z].ch[] == y) ? rotate(x) : rotate(y);
//如果x和y同为左儿子或者右儿子先旋转y
//如果x和y不同为左儿子或者右儿子先旋转x
//如果不双旋的话,旋转完成之后树的结构不会变化
rotate(x);
}
if (goal == )
root = x;
}
inline void insert(int x) {
int now = root, fa = ;//当前节点now和now的父节点fa
while (now&&a[now].val != x) {//当now存在并且没有移动到当前的值
fa = now;//父节点变为now
now = a[now].ch[x > a[now].val];//x大于当前位置则now向右,否则now向左
}
if (now)//这个值出现过
a[now].num++;//值增加
else {//这个值第一次出现,要新建一个节点来存放
now = ++len;
if (fa)//父节点不是根节点(0)
a[fa].ch[x > a[fa].val] = now;
//初始化节点
a[now].ch[] = a[now].ch[] = ;
a[now].siz = ;
a[now].num = ;
a[now].fa = fa;
a[now].val = x;
}
splay(now, );
}
inline void Find(int x) {//查找x的位置,并将其旋转到根节点
int now = root;
if (!now)return;//数为空
while (a[now].ch[x > a[now].val] && x != a[now].val)////当存在儿子并且当前位置的值不等于x
now = a[now].ch[x > a[now].val];
splay(now, );//把当前位置旋转到根节点
}
inline int Next(int x, int flag) {//查找x的前驱(0)或者后继(1)
Find(x);
int now = root;
if (a[now].val > x&&flag)return now;//如果当前节点的值大于x并且要查找的是后继
if (a[now].val < x && !flag)return now;//如果当前节点的值小于x并且要查找的是前驱
now = a[now].ch[flag];//查找后继的话在右儿子上找,前驱在左儿子上找
while (a[now].ch[flag ^ ])now = a[now].ch[flag ^ ];
return now;
}
inline void Delete(int x) {//删除一个x
int last = Next(x, );//查找x的前驱
int next = Next(x, );//查找x的后继
splay(last, ), splay(next, last);
//将前驱旋转到根节点,后继旋转到根节点下面
//很明显,此时后继是前驱的右儿子,x是后继的左儿子,并且x是叶子节点
int now = a[next].ch[];//后继的左儿子,也就是x
if (a[now].num > ) {//超过一个就删除一个
a[now].num--;
splay(now, );
}
else
a[next].ch[] = ;//直接删除 }
inline int kth(int k) {//查找第k小的数
int now = root;
if (a[now].siz < k)
return ;
while () {
int y = a[now].ch[];//y是左儿子
if (k > a[y].siz + a[now].num) {//如果排名比左儿子的大小和当前节点的数量要大
k -= a[y].siz + a[now].num;//排名减小
now = a[now].ch[];//定在右儿子上找
}
else {
if (k <= a[y].siz)
now = y;
else
return a[now].val;
}
}
}
int main() {
int n;
read(n);
root = , len = ;
insert();
insert(-);
while (n--) {
int q, x;
read(q), read(x);
if (q == )
insert(x);
else if (q == )
Delete(x);
else if (q == ) {
Find(x);
printf("%d\n", a[a[root].ch[]].siz);
}
else if (q == )
printf("%d\n", kth(x + ));
else if (q == )
printf("%d\n", a[Next(x, )].val);
else if (q == )
printf("%d\n", a[Next(x, )].val);
}
}
无旋Treap(学习fzszkl巨佬)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + ;
int Siz[maxn], ls[maxn], rs[maxn], val[maxn], pos[maxn], root;
int cnt;
int send = ;
inline int Rand() {
send ^= send << ;
send ^= send >> ;
send ^= send << ;
return send;
}
inline int New(int x) {
cnt++;
pos[cnt] = Rand();
Siz[cnt] = ;
val[cnt] = x;
return cnt;
}
inline void up(int x) {
Siz[x] = Siz[ls[x]] + Siz[rs[x]] + ;
}
void split_size(int x, int siz, int &A, int &B) {
if (x == )return (void)(A = B = );
if (siz <= Siz[ls[x]])
B = x, split_size(ls[x], siz, A, ls[x]);
else
A = x, split_size(rs[x], siz - Siz[ls[x]] - , rs[x], B);
up(x);
}
void split_val(int x, int v, int &A, int &B) {
if (x == )return (void)(A = B = );
if (v < val[x])
B = x, split_val(ls[x], v, A, ls[x]);
else
A = x, split_val(rs[x], v, rs[x], B);
up(x);
}
int Merge(int A, int B) {
if (A == || B == )return A | B;
int ans;
if (pos[A] > pos[B])ans = A, rs[A] = Merge(rs[A], B);
else ans = B, ls[B] = Merge(A, ls[B]);
up(ans);
return ans;
}
void dfs(int x) {
if (x == )
return;
printf("%d ", x);
dfs(ls[x]);
dfs(rs[x]);
}
void insert(int x) {
int A, B;
split_val(root, x - , A, B);
root = Merge(Merge(A, New(x)), B);
}
void Delete(int x) {
int A, B, C, D;
split_val(root, x - , A, B);
split_size(B, , C, D);//C就是删除的节点
root = Merge(A, D);
}
int Rank(int x) {//查x的排名
int A, B, ans;
split_val(root, x - , A, B);
ans = Siz[A] + ;
root = Merge(A, B);
return ans;
}
int getR(int x) {//查第x名是什么
int A, B, C, D, ans;
split_size(root, x - , A, B);
split_size(B, , C, D);
ans = val[C];
Merge(Merge(A, C), D);
return ans;
}
int last(int x) {
int A, B, C, D, ans;
split_val(root, x - , A, B);
split_size(A, Siz[A] - , C, D);
ans = val[D];
Merge(Merge(C, D), B);
return ans;
}
int Next(int x) {
int A, B, C, D, Ans;
split_val(root, x, A, B);
split_size(B, , C, D);
Ans = val[C];
root = Merge(Merge(A, C), D);
return Ans;
}
int main() {
int n;
scanf("%d", &n);
while (n--) {
int opt, x;
scanf("%d%d", &opt, &x);
if (opt == )
insert(x);
else if (opt == )
Delete(x);
else if (opt == )
printf("%d\n", Rank(x));
else if (opt == )
printf("%d\n", getR(x));
else if (opt == )
printf("%d\n", last(x));
else if (opt == )
printf("%d\n", Next(x));
}
return ;
}
[Bzoj3224][Tyvj1728] 普通平衡树(splay/无旋Treap)的更多相关文章
- [Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护 ...
- BZOJ - 3223 Tyvj 1729 文艺平衡树 (splay/无旋treap)
题目链接 splay: #include<bits/stdc++.h> using namespace std; typedef long long ll; ,inf=0x3f3f3f3f ...
- 【序列操作V】平衡树(无旋treap)
题目描述 维护一个队列,初始为空.依次加入 n(1≤n≤105)个数 ai(-109≤ai≤109),第 i(1≤i≤n)个数加入到当前序列第 bi(0≤bi≤当前序列长度)个数后面.输出最终队列. ...
- [模板] 平衡树: Splay, 非旋Treap, 替罪羊树
简介 二叉搜索树, 可以维护一个集合/序列, 同时维护节点的 \(size\), 因此可以支持 insert(v), delete(v), kth(p,k), rank(v)等操作. 另外, prev ...
- 浅谈无旋treap(fhq_treap)
一.简介 无旋Treap(fhq_treap),是一种不用旋转的treap,其代码复杂度不高,应用范围广(能代替普通treap和splay的所有功能),是一种极其强大的平衡树. 无旋Treap是一个叫 ...
- [转载]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
转载自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182491.html 今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和t ...
- [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...
- 洛谷 - P3391 【模板】文艺平衡树(Splay) - 无旋Treap
https://www.luogu.org/problem/P3391 使用无旋Treap维护序列,注意的是按顺序插入的序列,所以Insert实际上简化成直接root和Merge合并,但是假如要在序列 ...
- Luogu 3369 / BZOJ 3224 - 普通平衡树 - [无旋Treap]
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 https://www.luogu.org/problemnew/show/P3 ...
随机推荐
- ES6——generator-yield
yield 既可传参,又可以返回 第一个next()传参无效,只用来启动 如果函数前漏掉 * 就是普通函数 如果有yield会报错, ReferenceError: yield is not defi ...
- Solr的学习使用之(七)Solr高级查询facet、facet.pivot简介
以下转载自:http://hongweiyi.com/2013/03/apache-solr-facet-introduction/ 1.什么是Faceted Search Facet['fæsɪt] ...
- 脚本_获取本机 MAC 地址
#!bin/bash#作者:liusingbon#功能:获取本机 MAC 地址ip a s |awk 'BEGIN{print "本机 MAC 地址信息如下:"}/^[0-9]/{ ...
- Codeforces Round #425 (Div. 2) - A
题目链接:http://codeforces.com/contest/832/problem/A 题意:有n个棍子,两个人轮流取这些棍子,每个人每次只能去恰好k个棍子(不足k个则不能取),问先手取的棍 ...
- Could not resolve all files for configuration ':app:debugCompileClasspath'.解决方案
异常如下: Error:FAILURE: Build failed with an exception. * What went wrong:Could not resolve all files f ...
- Java EE的优越性主要表现在哪些方面
J2 EE的优越性主要表现在哪些方面 J2EE基于JAVA 技术,与平台无关. J2EE拥有开放标准,许多大型公司实现了对该规范支持的应用服务器.如BEA ,IBM,ORACLE等. J2EE提供相当 ...
- C#基础提升系列——C#任务和并行编程
C#任务和并行编程 我们在处理有些需要等待的操作时,例如,文件读取.数据库或网络访问等,这些都需要一定的时间,我们可以使用多线程,不需要让用户一直等待这些任务的完成,就可以同时执行其他的一些操作.即使 ...
- 日志管理工具logrotate
工作所需,需要管理脚本的打印日志,百度一圈,发现了logrotate这款工具,经测试确实挺好的! 话不多说,直接上重点,以便于以后需要时查看 命令: whereis logrotate 可以看到log ...
- python学习笔记(八)函数return多个值,列表推导式和交换两个变量的值
函数return多个值: 补充知识点:写代码得到时候少用全局变量: 1.不安全 2.会一直占着内存不释放 函数多个return值,那么会把这几个return的值都放在一个元组里面,然后返回 def h ...
- NVMe固态硬盘工具箱使用说明
https://www.bilibili.com/read/cv562989/ 浦科特NVMe固态硬盘工具箱使用说明 数码 2018-6-7 687阅读7点赞3评论 浦科特已经推出针对NVMe固态硬盘 ...