# 4月6日
参考代码(插入——分裂与合并):
inline void ins(int val){
//分裂
split(root , val , x , y);
root = merge(merge(x , newcode(val)) , y);
}
void split(int now , int val , int &x , int &y){
//按值分裂 :val 就是分裂的标准
if(!now) x = y = 0;
else{
//二叉搜索树,
if(fhq[now].val <= val){
x = now;
split(fhq[now].r , val , fhq[now].r , y);
}
else{
y = now;
split(fhq[now].l , val , x , fhq[now].l);
}
update(now);
}
}
inline void update(int now){
fhq[now].size = fhq[fhq[now].l].size + fhq[fhq[now].r].size + 1 ;
}
//和左偏树一样的合并操作
int merge(int x , int y){
if(!x || !y) return x + y;
if(fhq[x].key > fhq[y].key){
fhq[x].r = merge(fhq[x].r , y);
update(x);
return x;
}else{
fhq[y].l = merge(x , fhq[y].l);
update(y);
return y;
}
}
今天继续
请教了一下大佬(也许昨天我就要这么干的),再来模拟一次:
看下流程图:
这是情况一:树会偏向一边,
……有时间再补QAQ
# 4月10日
题目:普通平衡树
虽然是抄的,但我觉得蛮不错的……
自己打还是很难……
那个笔记不能上传真的很难受……
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int cnt , root;
int x, y, z;
struct node{
//左右子树,赋予的值val,堆排序关键字key,树上的高度;
int l , r , val , key , size;
}fhq[N];
inline int newcode(int val){
fhq[++cnt].val = val;
fhq[cnt].key = rand();
fhq[cnt].size = 1;
return cnt;
}
void update(int now) {
fhq[now].size = fhq[fhq[now].l].size + fhq[fhq[now].r].size + 1;
}
void split(int now, int val, int &x, int &y) {
//为空,就将带来的x,y赋值为0有两个作用.
//其中一个是断开两个子树,另一个则是保留当前节点不存在的事实
if(!now) x = y = 0;
else {
//val满足二叉查找树
//当前节点的val<=val,赋值x,向右找更大的y.
if(fhq[now].val <= val) {
//这里的x的意义是x或者当前节点,要注意
x = now;
split(fhq[now].r, val, fhq[now].r, y);
}
else {
//当前节点的val>val,赋值x,向左找更小的x.
y = now;
split(fhq[now].l, val, x, fhq[now].l);
}
update(now);
}
}
int merge (int x, int y) {
// 随便什么堆的合并
if(!x || !y) return x + y;
//这里的">"可以随便改,不会有影响.
if(fhq[x].key > fhq[y].key) {
fhq[x].r = merge(fhq[x].r, y);
update(x);
return x;
}
else {
//merge中x.val是严格小于y.val的
fhq[y].l = merge(x, fhq[y].l);
update(y);
return y;
}
}
void ins(int val) {
split(root, val, x, y);
//merge会返回合并后的根节点。
root = merge(merge(x, newcode(val)), y);
}
void del(int val) {
//先裂开成x、x + n两棵子树
split(root, val, x, z);
//然后是x - n, x
split(x, val - 1, x, y);
y = merge(fhq[y].l, fhq[y].r);
root = merge(merge(x, y), z);
}
//排名:排名定义为比当前数小的数的个数 +1
void getrank(int val) {
split(root, val - 1, x, y);
printf("%d\n", fhq[x].size + 1);
root = merge(x, y);
}
//查询排名为 x 的数
void getnum(int rank) {
int now = root;
while(now) {
if(fhq[fhq[now].l].size + 1 == rank) break;
//序号rank在左边
else if(fhq[fhq[now].l].size >= rank) now = fhq[now].l;
//rank在右边,由于在右边序号会减小,所以要将右子树前面的点数删去
else {
rank -= fhq[fhq[now].l].size + 1;
now = fhq[now].r;
}
}
printf("%d\n", fhq[now].val);
}
void pre(int val) {
//先按照对应的值分开,找左子树的最右边那个点
split(root, val - 1, x, y);
int now = x;
while(fhq[now].r) now = fhq[now].r;
printf("%d\n", fhq[now].val);
//记得合并回来
root = merge(x, y);
}
void nxt(int val) {
split(root, val, x, y);
int now = y;
while(fhq[now].l) now = fhq[now].l;
printf("%d\n", fhq[now].val);
root = merge(x, y);
}
int main() {
int n; cin >> n;
for(int i = 1; i <= n; i ++) {
int op, x; cin >> op >> x;
if(op == 1) ins(x);
if (op==2) del(x);
if (op==3) getrank(x);
if (op==4) getnum(x);
if (op==5) pre(x);
if (op==6) nxt(x);
}
return 0;
}