洛谷 P1503 鬼子进村

Description

传送门

Solution

无旋treap \((fhq-treap)\)

可能有些大材小用了,但是我毕竟是在练习,多写一遍总不是坏事。

基本上就是一个 \(fhq-treap\) 板子题。

不会的话,看这里 浅谈 fhq-treap(无旋treap)

我们把鬼子要摧毁的房子存到一个栈中,并 \(insert\) 到平衡树里。

每次修复的时候,退栈顶,并把栈顶从平衡树中删去。

那他能走到哪几个房子呢?

我们发现,其实就是当前房子 \(x\)后继 - 前驱 - 1

思考一下是不是,其实这题唯一的难点就在这里了。

我们还要打一个 \(vis\) 标记,标记是否被摧毁,如果已经被摧毁,且被困在当前点,直接输出 0。

Code

我把模板全打上去了,\(check_rk\)\(check_val\) 在这道题中不用写的。

但其实写上也不见得比不写码量多。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#define ls(x) t[x].ch[0]
#define rs(x) t[x].ch[1]

using namespace std;

const int N = 5e4 + 10;
int n, m, tot, root;
int stk[N], top;
struct Tree{
	int ch[2], siz, val, wei;
}t[N];
bool vis[N];
int a, b, c;

inline int read(){
	int x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
	return x;
}

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(t[x].val <= k){
		a = x;
		split(rs(x), k, 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 void insert(int k){
	t[++tot].val = k, t[tot].siz = 1, t[tot].wei = rand();
	split(root, k - 1, a, b);
	root = merge(merge(a, tot), b);
}

inline void remove(int k){
	split(root, k, a, b);
	split(a, k - 1, a, c);
	c = merge(ls(c), rs(c));
	root = merge(merge(a, c), b);
}

inline int check_rk(int k){
	split(root, k - 1, a, b);
	int ans = t[a].siz + 1;
	root = merge(a, b);
	return ans;
}

inline int check_val(int x, int k){
	if(k == t[ls(x)].siz + 1) return t[x].val;
	if(k <= t[ls(x)].siz) return check_val(ls(x), k);
	else return check_val(rs(x), k - t[ls(x)].siz - 1);
}

inline int check_pre(int k){
	return check_val(root, check_rk(k) - 1);
}

inline int check_next(int k){
	return check_val(root, check_rk(k + 1));
}

int main(){
	n = read(), m = read();
	char op;
	int x, last;
	insert(0), insert(n + 1);
	for(int i = 1; i <= m; i++){
		cin>>op;
		if(op == 'D'){
			x = read();
			vis[x] = 1, stk[++top] = x;
			insert(x);
		}
		if(op == 'R') vis[stk[top]] = 0, remove(stk[top--]);
		if(op == 'Q'){
			x = read();
			if(!vis[x])
				printf("%d\n", check_next(x) - check_pre(x) - 1);
			else printf("0\n");
		}
	}
	return 0;
}

End

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