https://www.luogu.org/problemnew/show/P3835

因为博主精力和实力有限,学不懂 fhq treap 了,因此只介绍 leafy tree 解法

leafy tree 的本质是一颗平衡线段树,它的根节点保存整颗树的信息,是不会变的,因此可以高效的实现可持久化

#include <bits/stdc++.h>
#define update(u) if(u -> left -> size) u -> size = u -> left -> size + u -> right -> size, u -> value = u -> right -> value
#define new_Node(a, b, c, d) (&(t[cnt++] = Node(a, b, c, d)))
#define merge(a, b) new_Node(a -> size + b -> size, b -> value, a, b)
#define ratio 4
using namespace std; const int N = 500000 + 10;
const int logN = 20; struct Node {
int size, value;
Node *left, *right;
Node () {}
Node (int a, int b, Node *c, Node *d) : size(a), value(b), left(c), right(d) {}
}*root[N], *null, t[N * logN * 11 / 10]; int n, cnt = 0; Node *maintain(Node *u) {
Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
if(cur -> left -> size > cur -> right -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> right = merge(cur -> left -> right, cur -> right), cur -> left = cur -> left -> left;
if(cur -> right -> size > cur -> left -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> left = merge(cur -> left, cur -> right -> left), cur -> right = cur -> right -> right;
return cur;
} Node *ins(Node *u, int x) {
Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
if(cur -> size == 1) cur -> left = new_Node(1, min(cur -> value, x), null, null), cur -> right = new_Node(1, max(cur -> value, x), null, null);
else if(x > cur -> left -> value) cur -> right = ins(cur -> right, x); else cur -> left = ins(cur -> left, x);
update(cur); return cur;
} Node *earse(Node *u, int x) {
Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
if(u -> size == 1 && u -> value != x) return cur;
if(cur -> left -> size == 1 && x == cur -> left -> value) *cur = *cur -> right;
else if(cur -> right -> size == 1 && x == cur -> right -> value) *cur = *cur -> left;
else if(x > cur -> left -> value) cur -> right = earse(cur -> right, x); else cur -> left = earse(cur -> left, x);
update(cur); return cur;
} int find(Node *u, int x) {
if(u -> size == 1) return u -> value;
return x > u -> left -> size ? find(u -> right, x - u -> left -> size) : find(u -> left, x);
} int Rank(Node *u, int x) {
// printf("u -> value = %d, x = %d\n", u -> value, x);
if(u -> size == 1) return 1;
return x > u -> left -> value ? Rank(u -> right, x) + u -> left -> size : Rank(u -> left, x);
} int main() {
scanf("%d", &n);
null = new Node(0, 0, 0, 0);
root[0] = new Node(1, INT_MAX, null, null);
for(int i = 1; i <= n; i++) {
int a, t, pre;
scanf("%d %d %d", &pre, &t, &a);
if(t == 1) root[i] = maintain(ins(root[pre], a));
if(t == 2) root[i] = maintain(earse(root[pre], a));
if(t == 3) printf("%d\n", Rank(root[pre], a)), root[i] = root[pre];
if(t == 4) printf("%d\n", find(root[pre], a)), root[i] = root[pre];
if(t == 5) {
int k = Rank(root[pre], a) - 1;
if(k == 0) puts("-2147483647");
else printf("%d\n", find(root[pre], k));
root[i] = root[pre];
}
if(t == 6) {
int k = Rank(root[pre], a + 1);
if(k == root[pre] -> size) puts("2147483647");
else printf("%d\n", find(root[pre], k));
root[i] = root[pre];
}
}
return 0;
}

关于新建节点时写

#define new_Node(a, b, c, d) (&(*st[cnt++] = Node(a, b, c, d)))

#define new_Node(a, b, c, d) (&(t[cnt++] = Node(a, b, c, d)))

的区别

leafy tree 实现可持久化平衡树的时候不能高效的垃圾回收,第一种就变成废物了,第二种在可持久化时更加高效

关于旋转的时候写

Node *maintain(Node *u) {
Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
if(cur -> left -> size > cur -> right -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> right = merge(cur -> left -> right, cur -> right), st[--cnt] = cur -> left, cur -> left = cur -> left -> left;
else if(cur -> right -> size > cur -> left -> size * ratio) cur -> left = maintain(cur -> left), cur -> right = maintain(cur -> right), cur -> left = merge(cur -> left, cur -> right -> left), st[--cnt] = cur -> right, cur -> right = cur -> right -> right;
return cur;
}

Node *maintain(Node *u) {
Node *cur = new_Node(u -> size, u -> value, u -> left, u -> right);
if(cur -> left -> size > cur -> right -> size * ratio) cur -> right = merge(cur -> left -> right, cur -> right), cur -> left = cur -> left -> left;
if(cur -> right -> size > cur -> left -> size * ratio) cur -> left = merge(cur -> left, cur -> right -> left), cur -> right = cur -> right -> right;
return cur;
}

的区别

第一种情况需要在插入和删除的时候调用 maintain,是整棵树平衡,比较正常

第二种情况在每次 update 之后 maintain,在可持久化时不能保证全局平衡,可能不太优秀?(这玩意是个玄学

关于 merge 的高效实现(因为博主太菜了就咕咕咕了

luoguP3835 [模板]可持久化平衡树的更多相关文章

  1. 洛谷.3835.[模板]可持久化平衡树(fhq treap)

    题目链接 对每次Merge(),Split()时产生的节点都复制一份(其实和主席树一样).时间空间复杂度都为O(qlogq).(应该更大些 因为rand()?内存真的爆炸..) 对于无修改的操作实际上 ...

  2. luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

    luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...

  3. Luogu P3835 【模板】可持久化平衡树(fhq Treap)

    P3835 [模板]可持久化平衡树 题意 题目背景 本题为题目普通平衡树的可持久化加强版. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本 ...

  4. [Luogu 3835]【模板】可持久化平衡树

    Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本): 插入x数 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作 ...

  5. 洛谷P3835 【模板】可持久化平衡树

    题目背景 本题为题目 普通平衡树 的可持久化加强版. 数据已经经过强化 感谢@Kelin 提供的一组hack数据 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作( ...

  6. P3835 【模板】可持久化平衡树

    题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本): 插入x数 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作) 查询x数的 ...

  7. LG3835 【模板】可持久化平衡树

    题意 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本): 插入x数 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作) 查询x数的排名 ...

  8. 2021.07.02 P1383 高级打字机题解(可持久化平衡树)

    2021.07.02 P1383 高级打字机题解(可持久化平衡树) 分析: 从可以不断撤销并且查询不算撤销这一骚操作可以肯定这是要咱建一棵可持久化的树(我也只会建可持久化的树,当然,还有可持久化并查集 ...

  9. 可持久化Trie & 可持久化平衡树 专题练习

    [xsy1629]可持久化序列 - 可持久化平衡树 http://www.cnblogs.com/Sdchr/p/6258827.html [bzoj4260]REBXOR - Trie 事实上只是一 ...

随机推荐

  1. Vue 简单的总结一

    let 变量 1. 局部作用域 2. 不会存在变量提升 3. 变量不能重复声明 const 变量 1. 局部作用域 2. 不会存在变量提升 3. 变量不能重复声明 4. 只能声明常量,不可变得量 th ...

  2. uboot启动正常,加载内核kernel启…

    先说现象吧:uboot能够正常启动,不过在kernel启动时却出现起不了的现象,停在这里 Uncompressing Linux.................................... ...

  3. RT2870移植到s3c2416后续验证无线…

    我的无线网卡显示的事ra0,所以把下面的wlan0换成ra0即可:视自己的情况而定 1. 打开无线网卡电源 iwconfig wlan0 txpower on 2. 列出区域内的无线网络 iwlist ...

  4. Game Develop Books

    [Working On] [Pending] 3.<实时计算机图形学> 4.<游戏编程精粹1> 5.<游戏编程精粹2> 6.<3D游戏引擎设计:实时计算机图形 ...

  5. 在cmd中 操作 数据库 MySQL 的一些命令

    环境变量配置配置好以后, 打开cmd 连接:mysql -h主机地址 -u用户名 -p用户密码 (注:u与root可以不用加空格,其它也一样) 断开:exit (回车) 创建授权:grant sele ...

  6. 使用GDB调试PHP代码,解决PHP代码死循环

    最近在帮同事解决Swoole Server问题时,发现有1个worker进程一直处于R的状态,而且CPU耗时非常高.初步断定是PHP代码中发生死循环. 下面通过一段代码展示如何解决PHP死循环问题. ...

  7. 关于equal和toString方法的实验报告

    一 实验目的 了解equal和toString方法 二 实验软件环境 操作系统:windows xp java version: "1.7.0_51" 开发工具:Eclipse S ...

  8. js数值和字符串比较的规则

    1.数值和字符串比较时 a.若字符串为数字字符串,则将字符串转为数字,再比较 b.若字符串不为数字字符串,则直接返回false,因为这里把字符串转为了NaN, 数字与NaN比较,都返回false

  9. Java 基于web service 暴露接口 供外部调用

    package cn.zr.out.outinterface; import java.text.SimpleDateFormat; import java.util.Date; import jav ...

  10. Docker学习笔记_Dockerfile基本知识

    Dockerfile由一行行命令语句组成,并支持以#开头的注释行. 1.编写一个Dockerfile文件 创建一个空的Docker工作目录,进入该目录,使用sudo vim Dockerfile指令新 ...