rt,link
AI 用不了,只有求助万能的谷友了
代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
#define which(x) (tree[tree[x].father].son[0] == x)
using namespace std ;
typedef long long lint ;
typedef long double dint ;
struct SplayTree {
struct Tree {
lint cnt ;
lint val ;
lint Size ;
lint son[2] ;
lint father ;
void init() {
cnt = val = 0 ;
Size = father = 0 ;
son[0] = son[1] = 0 ;
}
};
vector<Tree> tree ;
lint cnt, now, root ;
void init() {
tree.resize(int(1e5 + 5)) ;
for (int i = 1 ; i <= int(1e5 + 5) ; i ++)
tree[i].init() ;
}
// 更新:向上更新父节点的子树大小
void push_up(lint x) {
tree[x].Size += tree[x].cnt ;
tree[x].Size += tree[tree[x].son[0]].Size ;
tree[x].Size += tree[tree[x].son[1]].Size ;
}
// 旋转(单旋)将 x 点旋转到父结点处处
void revolve(lint x) {
lint fa = tree[x].father ; // 父节点
lint gf = tree[fa].father ; // 爷节点
bool whichfa = which(x) ; // 此节点是父节点的 左/右 儿子
bool whichgf = which(fa) ; // 父节点是爷节点的 左/右 儿子
tree[tree[x].son[!whichfa]].father = fa ; // 子节点过继(1)
tree[fa].son[whichfa] = tree[x].son[!whichfa] ; // 子节点过继(2)
tree[x].son[!whichfa] = fa ; // 旋转到父节点之上(1)改变父子关系
tree[gf].son[whichgf] = fa ; // 旋转到父节点之上(2)改变父子关系
tree[fa].father = x ; // 旋转到父节点之上(3)改变爷孙关系
tree[x].father = gf ; // 旋转到父节点之上(4)改变爷孙关系
push_up(fa), push_up(x) ; // 旋转到父节点之上(5)子树大小更新
}
// 旋转(双旋):将 x 点旋转到目标点 y 处
void Splay(lint x, lint y) {
lint fa, gf ;
if (x == y) return ;
while (tree[x].father != y) {
fa = tree[x].father ;
gf = tree[fa].father ;
if (gf != y) {
if (which(fa) == which(x)) // x, fa, gf 三点共线
revolve(fa) ; // 先旋转父节点
else // x, fa, gf 三点呈之字形
revolve(x) ; // 多旋转一次 x 节点
}
revolve(x) ;
}
if (!y)
root = x ;
}
// 插入:在平衡树中以 root 为根节点、val 为权值、fa 为父节点,插入一个节点
void insert(lint Root, lint val, lint fa) {
if (!Root) {
cnt ++ ;
tree[cnt].val = val ; // 传参:权值
tree[cnt].father = fa ; // 传参:父节点
tree[cnt].Size = tree[cnt].cnt = 1 ; // 初始化
if (val < tree[fa].val) tree[fa].son[0] = cnt ;
else tree[fa].son[1] = cnt ; // 判断插入的节点 x 与父节点 fa 的关系
if (cnt == 1) root = cnt ;
now = cnt ;
return ;
}
}
// 查找(1):查找第 x 小的元素
lint find_num(lint x) {
lint sum = 0 ;
lint Root = root ;
while (Root) {
if (tree[tree[Root].son[0]].Size + tree[Root].cnt >= x) { // 目标元素在当前节点或左子树中
if (tree[tree[Root].son[0]].Size < x) return Root ; // 目标元素是当前节点或其右子树的某个元素
else sum = Root, Root = tree[Root].son[1] ; // 继续在左子树中找
} else { // 目标元素在右子树中
x -= tree[tree[Root].son[0]].Size + tree[Root].cnt ; // 更新 x
sum = Root, Root = tree[Root].son[1] ; // 继续在左子树中找
}
}
return sum ;
}
// 查找(2):查找一个给定值 x 的排名
lint find_rank(lint val) {
lint Root = root ;
lint sum = 0, fa = 0 ;
while (Root) {
if (tree[Root].val < val) { // 当前节点及其左子树中的元素数目都小于 val
sum += tree[tree[Root].son[0]].Size = tree[Root].cnt ;
fa = Root, Root = tree[Root].son[1] ; // 进入右子树继续查找
} else {
fa = Root, Root = tree[Root].son[0] ; // 进入左子树继续查找
}
}
Splay(fa, 0) ;
return sum ;
}
// 查找(3):查找给定数 x 的前驱
lint find_Predecessor(lint x) {
lint Root = root, sum = 0 ;
while (Root) {
if (tree[Root].val >= x) // 当前节点值大于等于 x,前驱在左子树中
Root = tree[Root].son[0] ;
else sum = Root, Root = tree[Root].son[1] ; // 更新 sum,继续在右子树中查找
}
return sum ;
}
// 查找(4):查找给定数 x 的后继
lint find_Successor(lint x) {
lint sum = 0 ;
lint Root = root ;
while (Root) {
if (tree[Root].val < x) // 当前节点值小于 x,后继在右子树中
Root = tree[Root].son[1] ;
else sum = Root, Root = tree[Root].son[0] ; // 更新 sum,继续在左子树中查找
}
return sum ;
}
// 删除:删除一个值为 x 的节点
void Delete(lint x) {
lint Subsequent = find_Successor(x) ;
lint Precursor = find_Predecessor(x) ;
Splay(Precursor, 0), Splay(Subsequent, root) ;
lint rs = tree[root].son[1] ; // 根的右子树
lint rsls = tree[rs].son[0] ; // rs 的左子树
if (tree[rsls].cnt > 1)
tree[rsls].cnt --, tree[rsls].Size -- ;
else
tree[rs].son[0] = 0, tree[rsls].cnt --, tree[rsls].Size -- ;
push_up(rs), push_up(rs) ; // 更新节点大小
}
};
lint n ;
lint opt, x ;
SplayTree splaytree ;
signed main () {
cin >> n ;
for (lint i = 1 ; i <= n ; i ++) {
cin >> opt >> x ;
if (opt == 1) splaytree.insert(1, x, 1) ;
else if (opt == 2) splaytree.Delete(x) ;
else if (opt == 3) cout << splaytree.cnt - splaytree.find_rank(x) + 1 << '\n' ;
else if (opt == 4) cout << splaytree.find_num(x) << '\n' ;
else if (opt == 5) cout << splaytree.find_Predecessor(x) << '\n' ;
else if (opt == 6) cout << splaytree.find_Successor(x) << '\n' ;
}
return 0 ;
}