161 普通平衡树 Splay

老师的代码有点瑕疵,这里我补充一下,但是这里的瑕疵是学算法才能感知到的,如果是新人的话就是需要一一对比,即用老师的代码做洛谷 P3369 【模板】普通平衡树 这题是AC的,但是做洛谷 P6136 【模板】普通平衡树(数据加强版)就不一定了,该题有点裸但是也不是太裸,他输入数据异或加密了。你用老师的板子做就不一定能过,因为 get_rank(这是我写的函数名) 老师的代码如果这个数不存在,就有点问题了。这是问题1,问题2就是.查前驱/后继 ,最后也要splay一次,不然复杂度保证不了,即就两个数据测试点TLE。记住注释也要看看
```C++
//P6136 【模板】普通平衡树(数据加强版)
#include <iostream>
using namespace std;
#define ls(x) tr[x].son[0]
#define rs(x) tr[x].son[1]
const int MAX_N = 1e5 + 5, MAX_M = 1e6 + 5;
const int MAX_SIZE = MAX_N + MAX_M;
const int INF = (1 << 30) + 1;
struct Node {
int son[2]; //左右儿子
int parent; //父亲
int val; //节点权值
int cnt; //权值出现次数
int siz; //子树大小
void init(int parent_, int val_) {
parent = parent_, val = val_;
cnt = siz = 1;
}
} tr[MAX_SIZE];
int root, idx; //根节点编号,节点个数
void pushup(int x) {//x 下标
tr[x].siz = tr[ls(x)].siz + tr[rs(x)].siz + tr[x].cnt;
}
void rotate(int x) {//x 下标
int y = tr[x].parent, z = tr[y].parent;
int k = tr[y].son[1] == x;
tr[z].son[tr[z].son[1] == y] = x;
tr[x].parent = z;
tr[y].son[k] = tr[x].son[k ^ 1];
tr[tr[x].son[k ^ 1]].parent = y;
tr[x].son[k ^ 1] = y;
tr[y].parent = x;
pushup(y), pushup(x);
}
void splay(int x, int k) {
while (tr[x].parent != k) {
int y = tr[x].parent, z = tr[y].parent;
if (z != k) // 折转底,直转中
(ls(y) == x)^(ls(z) == y) ? rotate(x) : rotate(y);
rotate(x);
}
if (!k) root = x;
}
void insert(int v) { //插入数值v
int x = root, p = 0;
while (x && tr[x].val != v)
p = x, x = tr[x].son[v > tr[x].val];
if (x) tr[x].cnt++;
else {
x = ++idx;
tr[p].son[v > tr[p].val] = x;
tr[x].init(p, v);
}
splay(x, 0);
}
void find(int v) { //找到数值v并转到根
int x = root;
while (tr[x].son[v > tr[x].val] && v != tr[x].val)
x = tr[x].son[v > tr[x].val];
splay(x, 0);
}
int get_pre(int v) { //数值v前驱的编号
find(v);
int x = root;
if (tr[x].val < v) return x;
x = ls(x);
while (rs(x)) x = rs(x);
splay(x, 0);// 艹,少一句代码都TLE,#5样例TLE#6样例PASS
return x;
}
int get_suc(int v) { //数值v后继的编号
find(v);
int x = root;
if (tr[x].val > v) return x;
x = rs(x);
while (ls(x)) x = ls(x);
splay(x, 0);// #5样例PASS#6样例TLE
return x;
}
void del(int v) { //数值v删除
int pre = get_pre(v);
int suc = get_suc(v);
splay(pre, 0), splay(suc, pre);
int del = tr[suc].son[0];
if (tr[del].cnt > 1)
tr[del].cnt--, splay(del, 0);
else
tr[suc].son[0] = 0, splay(suc, 0);
}
int get_rank(int v) { //数值v排名
// 这里老师的代码有问题
// find(v);
// return tr[tr[root].son[0]].siz;
insert(v);
int res = tr[tr[root].son[0]].siz;
del(v);
return res;
}
int get_val_by_rank(int k) { //数值
int x = root;
while (1) {
int y = ls(x);
if (tr[y].siz + tr[x].cnt < k)
k -= tr[y].siz + tr[x].cnt,
x = rs(x);
else if (tr[y].siz >= k) x = y;
else break;
}
splay(x, 0);
return tr[x].val;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
insert(-INF);
insert(INF); //哨兵
int n, m;
scanf("%d%d", &n, &m);
int x;
while (n--) {
scanf("%d", &x);
insert(x);
}
int op, res = 0, last = 0;
while (m--) {
scanf("%d%d", &op, &x);
x ^= last;
if (op == 1) insert(x);
if (op == 2) del(x);
if (op == 3) res ^= (last = get_rank(x))/*,cout << "加密后:3 " << x << endl*/;
if (op == 4) res ^= (last = get_val_by_rank(x + 1))/*, cout << "加密后:4 " << x << endl*/;
if (op == 5) res ^= (last = tr[get_pre(x)].val)/*, cout << "加密后:5 " << x << endl*/;
if (op == 6) res ^= (last = tr[get_suc(x)].val)/*, cout << "加密后:6 " << x << endl*/;
}
cout << res << '\n';
return 0;
}
```