问题:
说明:
来 写 一 个 Treap。
问题链接:https://loj.ac/problem/104
提交记录:
输入案例:
传了一份测试数据:https://download.youkuaiyun.com/download/qq_28033719/12709334
我的代码:
知识准备
1、树堆:
是一种平衡树,由二叉搜索树(BST)分化而来,而且结合了堆排序特征(最大堆,最小堆),通过权值把最大或最小权值提升到根节点,那么树进行打结点时候,可以不用形成一条链表的情况,因此操作时间稳定在(Log n),具体有证明的。
2、左旋转 右旋转
左旋转:左手方向旋转,也叫做逆时针旋转,比如根节点3,右节点6, 3 -> 6 旋转就像是逆时针旋转。
左旋
3 3 6 6
/ \ / \ / \ / \
2 6 => 2 4 7 => 3 7
/ \ / \
4 7 2 4
右旋转:和左旋转相反
右旋反过来
6 3 6 3
/ \ / \ / \ / \
3 7 => 2 4 7 => 2 6
/ \ / \
2 4 4 7
3、前驱 后继
前驱:小于 target 的最大那个数
后继:大于 target 的最小那个数
4、具体代码:
我看了模板然后自己弄了下,还是弄成对象比较适合,也可以用数组(但数组的逻辑太反人类,我弄了好久没通过)
先放一个数组版的,再放一个对象版的,说实在,java提交记录看到都是100MS以上,换成数组也是,但是我如果用cpp写的代码就10ms一个记录,一样的逻辑,一样的判断但速度完全没法比。
数组版:
import java.util.Scanner;
public class Treap_Array {
private int BIN = 100005, LEFT = 0, RIGHT = 1, index = 0, ROOT = 0;
private int[] val = new int[BIN], num = new int[BIN],
size = new int[BIN], random = new int[BIN];
private int[][] child = new int[BIN][2];
public void pushup(int r) {
size[r] = num[r] + size[child[r][LEFT]] + size[child[r][RIGHT]];
}
// true - left, false - right
public int rotate(int r, boolean dir) {
int temp;
if(dir) {
temp = child[r][RIGHT];
child[r][RIGHT] = child[temp][LEFT];
child[temp][LEFT] = r;
} else {
temp = child[r][LEFT];
child[r][LEFT] = child[temp][RIGHT];
child[temp][RIGHT] = r;
}
pushup(r); pushup(temp); return temp;
}
public int insert(int r, int v) {
if(val[r] == 0) { // check val
r = ++ index;
val[r] = v; num[r] = size[r] = 1;
random[r] = (int)(Math.random() * BIN);
}
else if(val[r] == v) ++ num[r];
else {
int dir = val[r] > v ? 0 : 1;
child[r][dir] = insert(child[r][dir], v);
if(random[r] < random[child[r][dir]]) r = rotate(r, dir != 0);
}
pushup(r); return r;
}
public int delete(int r, int v) {
if(val[r] == 0) return r; // check val
else if(val[r] &g