洛谷 P2596 [ZJOI2006]书架
Description
Solution
这里介绍无旋treap (\(fhq-treap\))
关于模板有不会的同学可以去看我的博客 浅谈 fhq-treap(无旋treap)
这里只介绍本题思想:
由于题目还是对排名进行的操作,所以我们要按照子树大小进行分裂。
我们还要额外写一个函数来查找当前编号的书的位置。还要多记录一个 \(fa\) 表示当前节点的父亲节点,以便于查找排名。
操作:
-
Top: 把编号为 \(x\) 的书分裂出来,合并的时候直接合并到最前面。
-
Bottom: 同 \(Top\),分裂出来之后,直接合并到最后面。
-
Insert: 这个是最麻烦的,其实类似于文艺平衡树,合并的时候注意合并顺序,达到交换 \(x\) 和 \(x-1\) 或 \(x\) 和 \(x+1\) 的目的。(具体看代码)
-
Ask: 这个是最简单的,直接用上文中提到的查排名的函数查就行了。
-
Query: 这个是 \(fhq-treap\) 板子中的操作,查询排名为 \(x\) 的值。
还不懂的话,看代码理解吧。
Code
#include <bits/stdc++.h>
#define ls(x) t[x].ch[0]
#define rs(x) t[x].ch[1]
using namespace std;
const int N = 1e5 + 10;
struct Treap{
int ch[2], siz, val, wei, id, fa;
}t[N];
int n, m, tot, root;
int a, b, c;
int p[N], pos[N];
inline void pushup(int x){
t[x].siz = t[ls(x)].siz + t[rs(x)].siz + 1;
if(ls(x)) t[ls(x)].fa = x;
if(rs(x)) t[rs(x)].fa = x;
}
inline void split(int x, int k, int &a, int &b){
if(!x){
a = b = 0;
return;
}
if(k > t[ls(x)].siz){
a = x;
split(rs(x), k - t[ls(x)].siz - 1, rs(x), b);
}else{
b = x;
split(ls(x), k, a, ls(x));
}
pushup(x);
}
inline int merge(int x, int y){
if(!x || !y) return x | y;
if(t[x].wei <= t[y].wei){
rs(x) = merge(rs(x), y);
pushup(x);
return x;
}else{
ls(y) = merge(x, ls(y));
pushup(y);
return y;
}
}
inline int newnode(int k){
t[++tot].val = k, t[tot].siz = 1, t[tot].wei = rand(), t[k].id = tot;
return tot;
}
inline int query_pos(int x){
int res = t[ls(x)].siz + 1;
while(t[x].fa){
if(x == rs(t[x].fa))
res += t[ls(t[x].fa)].siz + 1;
x = t[x].fa;
}
return res;
}
inline void Top(int x){
int u = query_pos(pos[x]);
split(root, u - 1, a, b);
split(b, 1, b, c);
root = merge(merge(b, a), c);
}
inline void Bottom(int x){
int u = query_pos(pos[x]);
split(root, u - 1, a, b);
split(b, 1, b, c);
root = merge(merge(a, c), b);
}
inline void Insert(int x, int y){
int u = query_pos(pos[x]), d;
split(root, u - 1, a, b); // a: (<=u-1) b: (>=u)
split(b, 1, b, c); // b: (=u) c: (>u)
if(y == -1){
split(a, u - 2, a, d); // a: (<u-1) d: (=u-1)
root = merge(merge(merge(a, b), d), c);
}else{
split(c, 1, c, d); // c: (=u+1) d: (>u+1)
root = merge(merge(merge(a, c), b), d);
}
}
inline int Query(int x){
split(root, x - 1, a, b);
split(b, 1, b, c);
int ans = t[b].val;
root = merge(merge(a, b), c);
return ans;
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%d", &p[i]);
pos[p[i]] = newnode(p[i]);
root = merge(root, pos[p[i]]);
}
char s[10];
int op, x, y;
while(m--){
scanf("%s %d", s, &x);
if(s[0] == 'T') Top(x);
if(s[0] == 'B') Bottom(x);
if(s[0] == 'I'){
scanf("%d", &y);
if(y) Insert(x, y);
}
if(s[0] == 'A') printf("%d\n", query_pos(pos[x]) - 1);
if(s[0] == 'Q') printf("%d\n", Query(x));
}
return 0;
}