洛谷 P2596 [ZJOI2006]书架

Description

P2596 [ZJOI2006]书架

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;
}

End

posted @ 2021-08-17 16:32  xixike  阅读(48)  评论(0编辑  收藏  举报