tarjan杀我
更新: 2020.11.17
//对于查找频率较高的节点,使其处于离根节点相对较近的节点
//我们定义一个结点与他父亲的关系是x,
//那么在旋转时,他的父亲成为了他的!x儿子,
//并且那个上文中所说的“多余结点”,
//同时也是当前节点的!x儿子,
//但在旋转之后需要成为当前节点的“前”父节点的x儿子
// 1.插入 x 数
// 2.删除 x 数(若有多个相同的数,则只删除一个)
// 3.查询 x 数的排名(排名定义为比当前数小的数的个数 +1 )
// 4.查询排名为 x 的数
// 5.求 x 的前驱(前驱定义为小于 x,且最大的数)
// 6.求 x 的后继(后继定义为大于 x,且最小的数)
#include <bits/stdc++.h>
#define ll long long
#define _for(i,a,b) for(ll i = (a);i < (b); ++i)
#define sc scanf
#define pr printf
#define TLE ios::sync_with_stdio(false); cin.tie(0);
const int maxn = 500100;
const int INF = 0x3f3f3f3f;
using namespace std;
#define fa(x) tree[x].fath
#define ls(x) tree[x].ch[0]
#define rs(x) tree[x].ch[1]
struct Node {
int fath; //父节点
int ch[2]; //子节点
int cnt; //权值相同节点的数量
int w; //权值
int _size; //子树节点数量
}tree[maxn];
int root = 0; //保存当前根节点
int tot = 0; //保存不同权值的节点总数
void push_up(int u) { //计算儿子数
tree[u]._size = tree[tree[u].ch[0]]._size + tree[tree[u].ch[1]]._size + tree[u].cnt;
}
//判断节点是否为Splay的根节点
inline bool IsRoot(int x) {
return ls(fa(x)) != x && rs(fa(x)) != x;
//1.若x与fa(x)之间的边是虚边,那么它的父亲的孩子中不会有他(不在同一个splay内)
//2. splay的根节点与其父亲之间的边是虚边
}
#define id(x,y) tree[x].ch[1] == y
void rotate(int x) { //单旋
int y = fa(x);
int z = fa(y);
int k = id(y,x); // k = 1 则x是y的右儿子
// k = 0 则x是y的左儿子
//这里如果不判断y是否根节点,那么当y是根节点的时候,0节点的儿子就会被更新为x
//这样x就永远不能被判断为根节点,也就会无限循环下去了
//但是这里不更新x的父亲的话就会出现无限递归的情况
if(!IsRoot(y))
tree[z].ch[id(z,y)] = x; // y < z -> x < z;
fa(x) = z; // y > z -> x < z;
tree[y].ch[k] = tree[x].ch[k ^ 1]; // 如果当前节点是x的k孩子,旋转之后则必是y的!k孩子
fa(tree[x].ch[k ^ 1]) = y;
tree[x].ch[k ^ 1] = y; // 若x是y的左儿子,则y必是x的右儿子,反之同理
fa(y) = x;
push_up(y);
push_up(x);
}
void Splay(int x, int goal) {
while(fa(x) != goal) {
int y = fa(x);
if(fa(y) != goal)
rotate( (ls(y) == x) ^ (ls(fa(y)) == y) ? x : y );
rotate(x);
}
if(goal == 0) { //更新当前根节点
root = x;
}
}
inline void Find(int x) {
int u = root;
if(!u) return;
while(tree[u].ch[x > tree[u].w] && x != tree[u].w) {
u = tree[u].ch[x > tree[u].w];
}
Splay(u,0); //每次查找更新根节点
}
// 5.求 x 的前驱(前驱定义为小于 x,且最大的数)
// 6.求 x 的后继(后继定义为大于 x,且最小的数)
inline int Next(int x,int f) { //前驱 f = 0;
//后继 f = 1;
Find(x);
int u = root;
if(tree[u].w > x && f) return u; //后继
if(tree[u].w < x && !f) return u; //前驱
u = tree[u].ch[f];
while(tree[u].ch[f ^ 1]) {
u = tree[u].ch[f ^ 1];
}
return u;
}
// 2.删除 x 数(若有多个相同的数,则只删除一个)
inline void Delete(int x) {
int last = Next(x,0); //查找前驱
int next = Next(x,1); //查找后继
Splay(last,0);
Splay(next,last);
int del = tree[next].ch[0];
if(tree[del].cnt > 1) {
tree[del].cnt--;
Splay(del,0);
}
else {
tree[next].ch[0] = 0;
}
return;
}
// 1.插入 x 数
inline void Insert(int x) {
int now = root, fa = 0;
while(now && tree[now].w != x) {
fa = now;
now = tree[now].ch[x > tree[now].w];
}
if(now) { //存在权值为x的节点
tree[now].cnt++;
}
else { //不存在权值为x的节点,创建新节点
now = ++tot;
if(fa) {
tree[fa].ch[x > tree[fa].w] = now;
}
tree[tot].ch[0] = 0;
tree[tot].ch[1] = 0;
tree[tot].fath = fa;
tree[tot].w = x;
tree[tot].cnt = 1;
tree[tot]._size = 1;
}
Splay(now,0);
}
// 4.查询排名为 x 的数
inline int K_th(int x) {
int u = root;
if(tree[u]._size < x) {
return false;
}
while(1) {
int y = tree[u].ch[0];
if(x > tree[y]._size + tree[u].cnt) { //排名在u之后
x -= tree[y]._size + tree[u].cnt;
u = tree[u].ch[1];
}
else if(tree[y]._size >= x) {
u = y;
}
else {
return tree[u].w;
}
}
}
int main() {
int T;
sc("%d",&T);
int opt,x;
Insert(-2147483647);
Insert(+2147483647);
while(T--) {
sc("%d",&opt);
if(opt == 1) {
sc("%d",&x);
Insert(x);
}
else if(opt == 2) {
sc("%d",&x);
Delete(x);
}
else if(opt == 3) {
sc("%d",&x);
Find(x);
pr("%d\n",tree[tree[root].ch[0]]._size);
}
else if(opt == 4) {
sc("%d",&x);
pr("%d\n",K_th(x+1));
}
else if(opt == 5) {
sc("%d",&x);
pr("%d\n",tree[Next(x,0)].w);
}
else if(opt == 6) {
sc("%d",&x);
pr("%d\n",tree[Next(x,1)].w);
}
}
return 0;
}