STL
咳咳 过题专用
#include <bits/stdc++.h>
using namespace std;
int n, m, k;
vector<int> v;
int main() {
ios::sync_with_stdio(0);
cin >> n;
for (int i = 1, op, x; i <= n; ++i) {
cin >> op >> x;
auto it = lower_bound(v.begin(), v.end(), x);
switch (op) {
case 1:
//插入x数
v.insert(it, x);
break;
case 2:
//删除x数 若有多个相同的数 因只删除一个
v.erase(it);
break;
case 3:
//查询x数的排名 排名定义为比当前数小的数的个数+1
cout << it - v.begin() + 1 << endl;
break;
case 4:
//查询排名为x的数
cout << v[x - 1] << endl;
break;
case 5:
//求x的前驱 前驱定义为小于x 且最大的数
cout << v[it - v.begin() - 1] << endl;
break;
case 6:
//求x的后继 后继定义为大于x 且最小的数
cout << *upper_bound(v.begin(), v.end(), x) << endl;
}
}
return 0;
}
Splay
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
namespace Splay {
int f[N];//父节点
int ch[N][2];//俩儿子
int key[N];//val 关键字
int cnt[N];//记录和i节点相同val的个数
int size[N];//包括i的子树的大小
int sz;//整棵树的大小
int root;
inline int pre();
inline void Delete(int x);
inline int next();
inline void clear(int x) {//清空 用于删除之后
ch[x][0] = ch[x][1] = f[x] = cnt[x] = key[x] = size[x] = 0;
}
inline bool get(int x) {//判断当前节点是它父节点的左儿子还是右儿子
return ch[f[x]][1] == x;
}
inline void update(int x) {//更新size 用于发生修改之后
if (x) {
size[x] = cnt[x];
if (ch[x][0]) size[x] += size[ch[x][0]];
if (ch[x][1]) size[x] += size[ch[x][1]];
}
}
inline void rotate(int x) {
int old = f[x];//x的父节点
int oldf = f[old];//父节点的父节点
int whichx = get(x);
//假设x是old左儿子 现在要使旋转后 x是old父亲
//旋转的时候 把x的右儿子给old作为左儿子
ch[old][whichx] = ch[x][whichx ^ 1];
f[ch[old][whichx]] = old;
//这个时候x的新的右儿子就是old 其父亲就是原来父亲的父亲
ch[x][whichx ^ 1] = old;
f[old] = x;
f[x] = oldf;
//然后修改oldf的儿子信息 本来是old的地方现在是x了
if (oldf)
ch[oldf][ch[oldf][1] == old] = x;
update(old);
update(x);
}
inline void splay(int x) {
for (int fa; (fa = f[x]); rotate(x)) {
//fa先取f[x] 如果f[fa]存在的话 也就是三代关系 需要先旋转f[x]
//如果不存在 只有两代 就先旋转x本身
if (f[fa])
rotate((get(x) == get(fa)) ? fa : x);
}
root = x;
}
inline void insert(int x) {//插入
if (root == 0) {//空树
sz++;
ch[sz][0] = ch[sz][1] = f[sz] = 0;
root = sz;
size[sz] = cnt[sz] = 1;
key[sz] = x;
return;
}
int now = root;
int fa = 0;
while (1) {
if (x == key[now]) {
cnt[now]++;
update(now);
update(fa);
splay(now);
break;
}
fa = now;
now = ch[now][key[now] < x];
if (now == 0) {//创建新的节点
sz++;
ch[sz][0] = ch[sz][1] = 0;
f[sz] = fa;
size[sz] = cnt[sz] = 1;
ch[fa][key[fa] < x] = sz;
key[sz] = x;
update(fa);
splay(sz);
break;
}
}
}
inline int value_rank(int x) {//查询v的排名
int ans = 0;
int now = root;
while (1) {
if (x < key[now]) {
now = ch[now][0];
} else {
//如果在右子树里
ans += (ch[now][0] ? size[ch[now][0]] : 0);//先把左子树的大小加上
if (x == key[now]) {
splay(now);//先旋转 emmm不旋转会咋样?
return ans + 1;
}
ans += cnt[now];//再把中间的加上
now = ch[now][1];//往右子树走
}
}
}
inline int rank_value(int x) {//找到排名为x的点
int now = root;
while (1) {
if (ch[now][0] && x <= size[ch[now][0]])
now = ch[now][0];
else {
int tmp = (ch[now][0] ? size[ch[now][0]] : 0) + cnt[now];
if (x <= tmp) return key[now];
x -= tmp;
now = ch[now][1];
}
}
}
//------------------------------------
inline int Pre(int x) {//求前驱节点
insert(x);
int res = key[pre()];
Delete(x);
return res;
}
inline int pre() {
int now = ch[root][0];
while (ch[now][1]) now = ch[now][1];
return now;
}
//------------------------------------
inline int Suf(int x) {//求后继节点
insert(x);
int res = key[next()];
Delete(x);
return res;
}
inline int next() {
int now = ch[root][1];
while (ch[now][0])now = ch[now][0];
return now;
}
inline void Delete(int x) {
int whatever = value_rank(x);
if (cnt[root] > 1) {
cnt[root]--;
update(root);
return;
}
//只有根节点 且根节点只有一个
if (!ch[root][0] && !ch[root][1]) {
clear(root);
root = 0;
return;
}
//只有一个孩子
if (!ch[root][0]) {
int oldroot = root;
root = ch[root][1];
f[root] = 0;
clear(oldroot);
return;
} else if (!ch[root][1]) {
int oldroot = root;
root = ch[root][0];
f[root] = 0;
clear(oldroot);
return;
}
//有两个儿子
int leftbig = pre();
int oldroot = root;
splay(leftbig);
ch[root][1] = ch[oldroot][1];
f[ch[oldroot][1]] = root;
clear(oldroot);
update(root);
return;
}
}
using namespace Splay;//不能使用结构体封装 = = 爆栈了
//我就不明白了 treap也差不多大小 怎么就它能封装啊 吐血
int main() {
ios::sync_with_stdio(0);
cin >> n;
for (int i = 1, op, x; i <= n; ++i) {
cin >> op >> x;
switch (op) {
case 1:
//插入x数
insert(x);
break;
case 2:
//删除x数 若有多个相同的数 因只删除一个
Delete(x);
break;
case 3:
//查询x数的排名 排名定义为比当前数小的数的个数+1
cout << value_rank(x) << endl;
break;
case 4:
//查询排名为x的数
cout << rank_value(x) << endl;
break;
case 5:
//求x的前驱 前驱定义为小于x 且最大的数
cout << Pre(x) << endl;
break;
case 6:
//求x的后继 后继定义为大于x 且最小的数
cout << Suf(x) << endl;
}
}
return 0;
}
Treap 自平衡二叉查找树
一个随机附加域满足堆的性质的二叉搜索树
学习来源 - 这位大佬学的还很详细,值得瞧瞧
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
struct Treap {//Tree heap 树堆板子
Treap() {
init();
}
struct node {
int l, r;//俩儿子
int val;//节点的值 也叫关键码
int data;//节点的优先级
int num;//有多少个与当前节val相等的节点 包括自身
int size;//节点有多少个后辈 包括自身
} t[N];
int tot;
int root;//根节点
int getNode(int val) {
++tot;
t[tot] = {0, 0, val, rand(), 1, 1};//随机数分配优先级
return tot;
}
void update(int p) {//求size 左子树的大小+右子树的大小+本人那一堆相同的兄弟
t[p].size = t[t[p].l].size + t[t[p].r].size + t[p].num;
}
void build() {//建树
getNode(INT_MIN); //插入负无穷的 - 根节点
getNode(INT_MAX);//插入正无穷点 - 根节点的右节点
//建这两个点 目的是为了防止平衡树退化成链
root = 1;
t[1].r = 2;
update(root);
}
void RightRotate(int &p) {//右旋 旋转的同时修改了节点
int q = t[p].l;
t[p].l = t[q].r;
t[q].r = p;
p = q;
update(t[p].r);//更新右孩子的Size
update(p);
}
void LeftRotate(int &p) {//左旋 zag
int q = t[p].r;
t[p].r = t[q].l;
t[q].l = p;
p = q;
update(t[p].l);//更新左孩子的Size
update(p);
}
//----------------------------------
void insert(int val) {
INSERT(root, val);
}
void INSERT(int &p, int val) {
if (p == 0) {//节点不存在 并已经找到其应有的位置
p = getNode(val);
return;
}
if (val == t[p].val) {//val值已经存在
t[p].num++;
update(p);
return;
}
if (val < t[p].val) {//往左子树延伸
INSERT(t[p].l, val);
if (t[p].data < t[t[p].l].data) {//比较优先级
RightRotate(p);
}
} else {//往右子树延伸
INSERT(t[p].r, val);
if (t[p].data < t[t[p].r].data) {
LeftRotate(p);
}
}
update(p);
}
//----------------------------------
void Delete (int val){ //好难受啊 delete被用了
DELETE(root,val);
}
void DELETE(int &p, int val) {
if (p == 0)return;
if (val == t[p].val) {
if (t[p].num > 1) {
t[p].num--;
update(p);
return;
}
if (t[p].l || t[p].r) {
if (t[p].r == 0 || t[t[p].l].data > t[t[p].r].data) {
//如果右子树不存在 或者左子树的优先级大于右子树的
//右旋后再往右子树下延伸
RightRotate(p);
DELETE(t[p].r, val);
} else {//否则就左旋 再往左子树下延伸
LeftRotate(p);
DELETE(t[p].l, val);
}
update(p);
} else p = 0;
return;
}
if (val < t[p].val) DELETE(t[p].l, val);
else DELETE(t[p].r, val);
update(p);
}
//----------------------------------
int value_rank(int val){
return Sort(root, val) - 1;
}
int Sort(int p, int val) {//查询val值的排序 由值得出排名
if (p == 0)return 0;
if (val == t[p].val) return t[t[p].l].size + 1;//左子树的个数+1
if (val < t[p].val) return Sort(t[p].l, val);
return Sort(t[p].r, val) + t[t[p].l].size + t[p].num;
}
//----------------------------------
int rank_value(int k){//由排名得出值
return Value(root, k + 1);
}
int Value(int p, int k) {//由排名得出值
if (p == 0)return INT_MAX;//如果不存在 返回最大值
if (t[t[p].l].size >= k)
return Value(t[p].l, k);
if (t[t[p].l].size + t[p].num >= k)//根节点
return t[p].val;
return Value(t[p].r, k - t[t[p].l].size - t[p].num);
}
//----------------------------------
int Pre(int val) {//求值得前驱节点的值 如果整棵树只有根节点 返回的是的就是root
//记val的节点为p 求pre的值
int pre = 1;
int p = root;//从根节点开始往下找
while (p) {
if (val == t[p].val) {//如果等于当前节点
if (t[p].l > 0) {//往左子树的右子树最右端找
p = t[p].l;
while (t[p].r > 0) p = t[p].r;
pre = p;
}
break;
}
//移动pre指针
if (t[p].val < val && t[p].val > t[pre].val) pre = p;
//根据val的大小 往下深入
if (val < t[p].val) p = t[p].l;
else p = t[p].r;
}
return t[pre].val;
}
//----------------------------------
int Suf(int val) {//求后继节点的值
int suf = 2;
int p = root;
while (p) {
if (val == t[p].val) {
if (t[p].r > 0) {
p = t[p].r;
while (t[p].l > 0) {
p = t[p].l;
}
suf = p;
}
break;
}
//移动pre指针
if (t[p].val > val && t[p].val < t[suf].val) suf = p;
if (val < t[p].val) p = t[p].l;
else p = t[p].r;
}
return t[suf].val;
}
void init() {
tot = 0;
build();
}
};
int main() {
ios::sync_with_stdio(0);
Treap t;
cin >> n;
for (int i = 1, op, x; i <= n; ++i) {
cin >> op >> x;
switch (op) {
case 1:
//插入x数
t.insert(x);
break;
case 2:
//删除x数 若有多个相同的数 因只删除一个
t.Delete(x);
break;
case 3:
//查询x数的排名 排名定义为比当前数小的数的个数+1
cout << t.value_rank(x) << endl;
break;
case 4:
//查询排名为x的数
cout << t.rank_value(x) << endl;
break;
case 5:
//求x的前驱 前驱定义为小于x 且最大的数
cout << t.Pre(x) << endl;
break;
case 6:
//求x的后继 后继定义为大于x 且最小的数
cout << t.Suf(x) << endl;
}
}
return 0;
}
留一个坑给AVL 等大四了再来撸一撸板子
AVL