[Ybt gold medal navigation 4-4-1] [luogu P2596] maintenance bookshelf / bookshelf / non-rotating treap template

Maintenance bookshelf / bookshelf / non-rotating treap template

Topic link: ybt gold medal navigation 4-4-1 / luogu P2596

Main idea 2.

There is a sorting, and then some operations:
put the position of a number to the front or the back, or move the position forward or backward by one grid, ask how many books are on a book, and ask for the xth number from the top. The number of the book.

Ideas

Seeing so many requirements in this question, I naturally thought of a balanced tree.
Here we use the non-rotating Treap to do it.

It is mainly to divide and merge the trees continuously, and then realize the operation.
For details on how to do each operation, see the code comments.

Code

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>

using namespace std;

struct Tree {
    
    
	int l, r, size, rank, val, fa;
}tree[2000001];
int n, m, x, root, dy[100001];
int r1, r2, r3, r4, tot, s, t;
string op;

int get_new(int val) {
    
    //建新点
	tot++;
	tree[tot] = (Tree){
    
    0, 0, 1, rand(), val, 0};
	return tot;
}

void up(int now) {
    
    //上递值
	tree[now].size = 1;
	if (tree[now].l) tree[now].size += tree[tree[now].l].size, tree[tree[now].l].fa = now;
	if (tree[now].r) tree[now].size += tree[tree[now].r].size, tree[tree[now].r].fa = now;
}

int merge(int root1, int root2) {
    
    //合并两个树
	if (!root1) return root2;
	if (!root2) return root1;
	if (tree[root1].rank < tree[root2].rank) {
    
    //合并主要就是每次通过比较树上面的大小值,可以直接确定一半
		tree[root1].r = merge(tree[root1].r, root2);
		up(root1);
		return root1;
	}
	else {
    
    
		tree[root2].l = merge(root1, tree[root2].l);
		up(root2);
		return root2;
	}
}

void split(int now, int kth, int &root1, int &root2) {
    
    //分离树(根据前后点个数)
	if (!now) {
    
    
		root1 = 0;
		root2 = 0;
		return ;
	}//这个就按着要求的前面个数类似二分的感觉分一下就可以
	if (tree[tree[now].l].size < kth) {
    
    
		root1 = now;
		split(tree[now].r, kth - tree[tree[now].l].size - 1, tree[now].r, root2);
	}
	else {
    
    
		root2 = now;
		split(tree[now].l, kth, root1, tree[now].l);
	}
	up(now);
}

void insert(int val) {
    
    //把新的点放进树里面
	root = merge(root, get_new(val));
}

int get_rank(int x) {
    
    //求出排名
	int re = tree[tree[x].l].size + 1;
	for (int now = x; tree[now].fa; now = tree[now].fa) {
    
    
		if (tree[tree[now].fa].r == now)
			re += tree[tree[tree[now].fa].l].size + 1;
	}
	return re;
}

int main() {
    
    
	srand(1919810);
	
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
    
    
		scanf("%d", &x);
		dy[x] = i;
		insert(x);
	}
	
	for (int i = 1; i <= m; i++) {
    
    
		cin >> op;
		if (op[0] == 'T') {
    
    
			scanf("%d", &s);
			s = get_rank(dy[s]);//把那个点放到最前面合并
			split(root, s, r1, r3);
			split(r1, s - 1, r1, r2);
			root = merge(r2, merge(r1, r3));
		}
		else if (op[0] == 'B') {
    
    
			scanf("%d", &s);//放到最后面合并
			s = get_rank(dy[s]);
			split(root, s, r1, r3);
			split(r1, s - 1, r1, r2);
			root = merge(r1, merge(r3, r2));
		}
		else if (op[0] == 'I') {
    
    
			scanf("%d %d", &s, &t);
			if (!t) continue;
			s = get_rank(dy[s]);
			if (t > 0) {
    
    //把它和它的后继合并
				split(root, s + 1, r3, r4);
				split(r3, s, r2, r3);
				split(r2, s - 1, r1, r2);
				root = merge(r1, merge(r3, merge(r2, r4)));
			}
			else {
    
    //把它和它的前驱合并
				split(root, s, r3, r4);
				split(r3, s - 1, r2, r3);
				split(r2, s - 2, r1, r2);
				root = merge(r1, merge(r3, merge(r2, r4)));
			}
		}
		else if (op[0] == 'A') {
    
    //排名加一既是位置
			scanf("%d", &s);
			printf("%d\n", get_rank(dy[s]) - 1);
		}
		else if (op[0] == 'Q') {
    
    //直接找,分离出来,再合并回去
			scanf("%d", &s);
			split(root, s - 1, r1, r2);
			split(r2, 1, r2, r3);
			printf("%d\n", tree[r2].val);
			root = merge(merge(r1, r2), r3);
		}
	}
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/113873139