http://www.lydsy.com/JudgeOnline/problem.php?id=3224
无力吐槽,无力吐槽,无力吐槽.......
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 ", tree.rank(b, tree.root)); else if(a==4) printf("%d ", tree.select(b, tree.root)->key); else if(a==5) printf("%d ", tree.pre(b)); else if(a==6) printf("%d ", 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
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
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]