书 架 书架 书架
题目描述见链接 .
最 初 想 法 \color{grey}{最初想法} 最初想法
使用 S p l a y Splay Splay维护
Input: 依次插入节点, 不断 初始插入 到上个节点的右子树中
Top : 将权值为 S S S的点 删去 , 再插入作为到 S p l a y Splay Splay的最左边儿子的左儿子
Bottom : 将权值为 S S S的点 删去 , 在插入作为 S p l a y Splay Splay的最右边儿子的右儿子
Insert : 将权值为 S S S的点 删去 , 设删去的点等级为 x x x, 将等级为 x + T − 1 x+T-1 x+T−1的点 S p l a y Splay Splay到根节点, 把 S S S点 插入之间 根节点 (不要在意语序…)
Ask : 直接将 S S S节点 S p l a y Splay Splay到根节点, 输出左子树大小即可
Query : 查询第 S S S大的元素
初始插入 : 不断将当前节点插入到 上个插入节点 的右子树即可, 不要忘记Splay到根节点
删去 : 直接前缀后缀删除法即可
插入之间 : 将该节点的未来
p
a
r
par
par的右儿子置为该节点, 该节点的右儿子置为
p
a
r
par
par原来的右儿子
正 解 部 分 \color{red}{正解部分} 正解部分
初始化序列 时不断将第 i i i 个元素插入作为第 i − 1 i-1 i−1 个元素的右子树 .
- T o p Top Top 操作: 直接将 i i i 元素旋转到根节点, 将其左子树变为 i i i的后继 的左儿子 .
- B o t t o m Bottom Bottom 操作: 直接将 i i i 元素旋转到根节点, 将其右子树变为 i i i的前驱 的右儿子 .
- I n s e r t Insert Insert 操作: 直接将 i i i 元素 与其 前驱/后继 的信息 进行交换即可 .
- A s k Ask Ask 操作: 直接将 i i i 旋转到根, 输出其左子树大小即可 .
- Q u e r y Query Query 操作: 查询第 K K K 大即可 .
实 现 部 分 \color{red}{实现部分} 实现部分
- 注意 r o t a t e rotate rotate 时 s i z e size size 的赋值顺序 .
- 交换时交换的是位置, 不是值, 只要将相关映射和对应位置上的值交换即可 .
#include<bits/stdc++.h>
#define reg register
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 80005;
int N;
int M;
int Mp[maxn];
char Smp[10];
namespace BBT{
int rot;
int node_cnt;
struct Node{ int v, fa, son[2], size; } T[maxn];
bool chk(int x){ return T[T[x].fa].son[0] != x; }
void rotate(int x){
int y = T[x].fa, z = T[y].fa;
int dir = chk(x), sn = T[x].son[dir^1];
if(y == rot) rot = x;
else T[z].son[chk(y)] = x; T[x].fa = z;
T[y].son[dir] = sn, T[sn].fa = y;
T[x].son[dir^1] = y, T[y].fa = x;
T[y].size = T[T[y].son[0]].size + T[T[y].son[1]].size + 1;
T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size + 1;
}
void Splay(int x, int aim=0){
while(T[x].fa != aim){
int y = T[x].fa, z = T[y].fa;
if(z != aim){
if(chk(x) == chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
}
int Kth(int k, int aim){
int ls = T[k].son[0];
if(T[ls].size + 1 == aim) return k;
else if(T[ls].size >= aim) return Kth(ls, aim);
return Kth(T[k].son[1], aim - T[ls].size - 1);
}
void Add_node(int x){
Mp[x] = ++ node_cnt, T[node_cnt] = (Node){ x, 0, {0,0}, 1 };
if(node_cnt > 1){
T[node_cnt-1].son[1] = node_cnt, T[node_cnt].fa = node_cnt - 1;
Splay(node_cnt);
}
}
void Top(int k){
Splay(k);
if(!T[k].son[0]) return ;
else if(!T[k].son[1]){ T[k].son[1] = T[k].son[0], T[k].son[0] = 0; return ; }
int ls = T[k].son[0];
int y = Kth(rot, T[ls].size+2);
T[y].son[0] = ls, T[ls].fa = y, T[k].son[0] = 0;
Splay(y);
}
void Bottom(int k){
Splay(k);
if(!T[k].son[1]) return ;
else if(!T[k].son[0]){ T[k].son[0] = T[k].son[1], T[k].son[1] = 0; return ; }
int ls = T[k].son[0], rs = T[k].son[1];
int y = Kth(rot, T[ls].size);
T[y].son[1] = rs, T[rs].fa = y, T[k].son[1] = 0;
Splay(y);
}
void Insert(int k, int opt){
if(!opt) return ;
Splay(k);
int rk = T[T[k].son[0]].size + 1, y = Kth(rot, rk + opt);
std::swap(Mp[T[k].v], Mp[T[y].v]);
std::swap(T[k].v, T[y].v);
}
void Ask(int k){ Splay(k); printf("%d\n", T[T[k].son[0]].size); }
void Query(int rk){ int y = Kth(rot, rk); printf("%d\n", T[y].v); }
}
void Work(){
scanf("%s", Smp);
int x = read();
if(Smp[0] == 'T') BBT::Top(Mp[x]);
else if(Smp[0] == 'B') BBT::Bottom(Mp[x]);
else if(Smp[0] == 'I') BBT::Insert(Mp[x], read());
else if(Smp[0] == 'A') BBT::Ask(Mp[x]);
else BBT::Query(x);
}
int main(){
N = read(), M = read();
BBT::rot = 1;
for(reg int i = 1; i <= N; i ++) BBT::Add_node(read());
while(M --) Work();
return 0;
}