http://www.lydsy.com/JudgeOnline/problem.php?id=3224

【BZOJ】3224: Tyvj 1728 普通平衡树(某不科学的oj)_bzoj

无力吐槽,无力吐槽,无力吐槽.......

bzoj竟然不能用time(0)我竟然不造!!re成一片。。。。。

(不管re没re,我也在我程序中找到了很多bug,,,一一修复了。。我的treap写的真渣。

这次我发现了treap的很多问题,有一个细节的地方。就是null的weight必须要最大(或最小),你的堆是最小(或最大)的话,所以要将null的weight的初值设置一下,否则在删除操作的时候会吧null旋转上去。。然后就,,

这个题还有一个hentai的地方,就是求前驱后继以及排名和第k小,全是坑,首先是有多个相同的要最小的,然后又是求前驱后继不是在树里面有的。。经过观赏大神们的代码,我一一解决了。现在放上代码

#include <cstdio>
#include <cstdlib>

using namespace std;
const int oo=~0u>>1;

struct Treap {
	struct node {
		node* ch[2];
		int key, size, wei, cnt; //多加一个维
		node(int _key, node* f) { ch[0]=ch[1]=f; key=_key; size=cnt=1; wei=rand(); }
		void pushup() { size=ch[0]->size+ch[1]->size+cnt; } //用cnt来更新
	}*null, *root;
	Treap() {
		null=new node(0, 0);
		null->size=null->cnt=0;  null->wei=oo; //细节
		root=null;
	}
	void rot(node* &rt, bool d) {
		node* c=rt->ch[!d]; rt->ch[!d]=c->ch[d]; c->ch[d]=rt;
		rt->pushup(); c->pushup();
		rt=c;
	}
	void insert(const int &key, node* &rt) {
		if(rt==null) { rt=new node(key, null); return; }
		if(key==rt->key) {
			rt->cnt++; rt->size++;
			return;
		}
		bool d=key>rt->key;
		insert(key, rt->ch[d]);
		if(rt->wei>rt->ch[d]->wei) rot(rt, !d); //我是弄成小根堆
		rt->pushup();
	}
	void remove(const int &key, node* &rt) {
		if(rt==null) return;
		bool d=key>rt->key;
		if(key==rt->key) {
			if(rt->cnt>1) { rt->cnt--; rt->size--; return; }
			d=rt->ch[0]->wei>rt->ch[1]->wei; //巧妙的用上了null的weight最大
			if(rt->ch[d]==null) {
				delete rt;
				rt=null;
				return;
			}
			rot(rt, !d);
			remove(key, rt->ch[!d]);
		}
		else remove(key, rt->ch[d]);
		rt->pushup();
	}
	node* select(int k, node* rt) {
		int s=rt->ch[0]->size+rt->cnt;
		if(k>=rt->ch[0]->size+1 && k<=s) return rt; //这里要注意,因为有多个相同值,所以要判断区间
		if(s>k) return select(k, rt->ch[0]);
		else return select(k-s, rt->ch[1]);
	}
	int rank(const int &key, node* rt) {
		if(rt==null) return 0;
		int s=rt->ch[0]->size+rt->cnt;
		if(key==rt->key) return rt->ch[0]->size+1; //这里要注意,返回的要是第一个
		if(key<rt->key) return rank(key, rt->ch[0]);
		else return s+rank(key, rt->ch[1]);
	}
	int suc(const int &k) {
		node* t=root;
		int ret=0;
		while(t!=null) {
			if(t->key>k) {
				ret=t->key;
				t=t->ch[0];
			}
			else t=t->ch[1];
		}
		return ret;
	}
	int pre(const int &k) {
		node* t=root;
		int ret=0;
		while(t!=null) {
			if(t->key<k) {
				ret=t->key;
				t=t->ch[1];
			}
			else t=t->ch[0];
		}
		return ret;
	}
};

int main() {
	int n, a, b;
	Treap tree;
	scanf("%d", &n);
	while(n--) {
		scanf("%d%d", &a, &b);
		if(a==1) tree.insert(b, tree.root);
		else if(a==2) tree.remove(b, tree.root);
		else if(a==3) printf("%d\n", tree.rank(b, tree.root));
		else if(a==4) printf("%d\n", tree.select(b, tree.root)->key);
		else if(a==5) printf("%d\n", tree.pre(b));
		else if(a==6) printf("%d\n", tree.suc(b));
	}
	return 0;
}

 

 


 

 

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案

Sample Input

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

Sample Output

106465
84185
492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-1e7,1e7]