题目链接: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)的更多相关文章

  1. [Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护 ...

  2. BZOJ - 3223 Tyvj 1729 文艺平衡树 (splay/无旋treap)

    题目链接 splay: #include<bits/stdc++.h> using namespace std; typedef long long ll; ,inf=0x3f3f3f3f ...

  3. 【序列操作V】平衡树(无旋treap)

    题目描述 维护一个队列,初始为空.依次加入 n(1≤n≤105)个数 ai(-109≤ai≤109),第 i(1≤i≤n)个数加入到当前序列第 bi(0≤bi≤当前序列长度)个数后面.输出最终队列. ...

  4. [模板] 平衡树: Splay, 非旋Treap, 替罪羊树

    简介 二叉搜索树, 可以维护一个集合/序列, 同时维护节点的 \(size\), 因此可以支持 insert(v), delete(v), kth(p,k), rank(v)等操作. 另外, prev ...

  5. 浅谈无旋treap(fhq_treap)

    一.简介 无旋Treap(fhq_treap),是一种不用旋转的treap,其代码复杂度不高,应用范围广(能代替普通treap和splay的所有功能),是一种极其强大的平衡树. 无旋Treap是一个叫 ...

  6. [转载]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

    转载自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182491.html 今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和t ...

  7. [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

    今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...

  8. 洛谷 - P3391 【模板】文艺平衡树(Splay) - 无旋Treap

    https://www.luogu.org/problem/P3391 使用无旋Treap维护序列,注意的是按顺序插入的序列,所以Insert实际上简化成直接root和Merge合并,但是假如要在序列 ...

  9. Luogu 3369 / BZOJ 3224 - 普通平衡树 - [无旋Treap]

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 https://www.luogu.org/problemnew/show/P3 ...

随机推荐

  1. 【记录】spring boot 全局捕获异常@ExceptionHandler与@Validated @RequestBody 配合使用

    @ExceptionHandler与@Validated @RequestBody 三者配合使用可以很好的做到入参校验,具体demo如下: 接口 import org.springframework. ...

  2. Xshell设置密钥登录确保Linux

    用Xshell设置密匙登陆服务器, 第一步.使用Xshell生成密钥 我们打开熟悉的XSHELL软件,然后在工具-新建用户密钥生成向导. 到了生成密钥参数界面,我们这里需要选择RSA密钥类型,以及密钥 ...

  3. 用python 写一个nagios插件 监控http内容(转载)

     nagios自带的http-check插件主要是检测地址url是否可以访问,在web+中间件的架构中容易出现url能访问,但是后台中间件拓机的情况,因为最近在自学python,所以写了个脚本检测ur ...

  4. [Luogu2015]二叉苹果树(树形dp)

    [Luogu2015] 二叉苹果树 题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. ...

  5. python_012

    一.内置函数 1.sorted()排序函数 a:语法sorted(Iterable,key = None,reverse = False) Iterable:可迭代对象;key:排序规则(函数) ls ...

  6. 【HDOJ6635】Nonsense Time(时间倒流,lis)

    题意:给定n个数的数列,第i个数为a[i],刚开始所有位置都处于禁用状态,第i次之后位置p[i]变为可用,求每次变化后的lis长度 n,a[i],p[i]<=5e4 保证a[i],p[i]均为随 ...

  7. redux简单使用

    在前面的随便中有简单的使用过redux和react-redux,但是感觉写在一起,总是理不清楚,后面看了技术胖老师关于redux的视频后,感觉自己又有了新的理解,在这里简单记录一下. 项目准备 首先安 ...

  8. 让VirtualBox虚拟机实现开机自动后台运行

    转至:http://www.cnblogs.com/top5/archive/2012/01/19/2326234.html 测试环境:Host OS: Windows 7 x64 Guest OS: ...

  9. sqlserver连接-2

    本地连接 方法1. 方法2. 远程连接 如果无法通过IP地址远程连接你的SQL Server 2008服务器,可以参考下面的内容进行设置. 在进行下述设置之前,应该确保你的网络已经安装设置完毕,服务器 ...

  10. ECharts t图表组件使用心得

    1.使用较多的是“柱状图”和“折线图”: 2.数据列的展示不能够直接输入字符串,正确的做法是将字符串转换成数字类型,这样在生成的图表上才会显示最大值和最小值: 3.对上 1 点的补充,数据列应该使用数 ...