洛谷 P3850 [TJOI2007]书架

Description

传送门

Solution

无旋treap \(fhq-treap\)

关于 \(fhq-treap\) 不会的同学可以去看我的博客 浅谈 fhq-treap(无旋treap)

一道经典的按区间大小分裂的题。

这道题中,我们要稍微修改 \(split\) 函数。

以前我们写过的大部分题目都是按数值来分裂的,这次我们换一种分裂参数。

我们以子树大小来分裂,这是为什么呢?

因为我们插入,查询时都是输入的排名,对于一棵平衡树来说,一个节点的左子树中的值都是小于它的数,右子树中的值都是大于它的数。

因此按子树大小来分裂刚好可以满足条件。

再说一些细节。

  • 输入的都是字符串,这个好说,我们给它映射一下,映射到一个数字上即可。

  • 对于刚开始的就有的 \(n\) 本书,因为排名是从 0 开始的,所以我们插入时要 \(insert(i - 1, cnt)\)

    \(cnt\) 就是一个字符串映射之后的数字)

  • 对于后来插入的 \(m\) 本书,思考一下,假设插入到第 \(x\) 位上,那么它就会变成第 \(x\) 本书,所以 \(insert(x, cnt)\)

结合代码理解一下吧

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 = 2e5;
struct Treap{
	int ch[2], val, siz, wei;
}t[N];
int n, m, q, tot, root, cnt;
int a, b, c;
char s[N][15];

inline void pushup(int x){
	t[x].siz = t[ls(x)].siz + t[rs(x)].siz + 1;
}

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(a), k - t[ls(x)].siz - 1, rs(a), b);
	}else{
		b = x;
		split(ls(b), k, a, ls(b));
	}
	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();
	return tot;
}

inline void insert(int k, int x){		//插入这里传两个参,一个是插到第几位,另一个是编号
	split(root, k, a, b);
	root = merge(a, merge(newnode(x), b));
}

inline int query(int k){
	split(root, k, a, b);
	split(b, 1, b, c);
	int rank = t[b].val;
	merge(a, merge(b, c));
	return rank;
}

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%s", s[++cnt]);
		insert(i - 1, cnt);			//插入道第 i - 1 位上
	}
	scanf("%d", &m);
	for(int i = 1; i <= m; i++){
		int x;
		scanf("%s %d", s[++cnt], &x);
		insert(x, cnt);
	}
	scanf("%d", &q);
	while(q--){
		int x;
		scanf("%d", &x);
		printf("%s\n", s[query(x)]);
	}
	return 0;
}

End

posted @ 2021-08-17 10:28  xixike  阅读(50)  评论(0编辑  收藏  举报