BZOJ 3224 Tyvj 1728 普通平衡树 (Treap)
2017-01-03 19:15
405 查看
BZOJ 3224 Tyvj 1728 普通平衡树
题目概述:
给n个操作,有6种操作:1.插入一个数
2.删除一个数(若该数有多个,那么只删除一个)
3.查询一个数的排名(若有多个,取最小)
4.查询一个排名对应数
5.查询一个数的前驱(小于该数的最大数)
6.查询一个数的后继(大于该数的最小数)
题目分析:
如题目,是一道平衡树的版题,可以选择使用Treap实现.注意可能会有相同的数出现,需要记录一下同样的数的个数.
代码:
数组版
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> using namespace std; const int maxn=100000+10; #define lc ch[u][0] #define rc ch[u][1] int ch[maxn][2],key[maxn],sz[maxn],rnd[maxn],cnt[maxn],id,root; void update(int u) { sz[u]=sz[lc]+sz[rc]+cnt[u]; } void rotate(int& u,int d)//旋转,d 0,left;1,right. { int v=ch[u][d^1]; ch[u][d^1]=ch[v][d]; ch[v][d]=u; update(u); update(u=v); } void insert(int& u,int val)//插入,注意维护结点的子树个数和 { if(!u) { u=++id; lc=rc=0; key[u]=val; rnd[u]=rand(); sz[u]=cnt[u]=1; return ; } if(key[u]==val) {++sz[u],++cnt[u];return ;} int d=key[u]<val; insert(ch[u][d],val);++sz[u]; if(rnd[ch[u][d]]<rnd[u]) rotate(u,d^1); } bool remove(int& u,int val)//删除,注意维护结点的子树个数和 { if(!u) return false; if(key[u]==val) { if(cnt[u]>1) return --sz[u],--cnt[u],true;//不止一个,直接删 if(!lc||!rc) return u=lc?lc:rc,true;//仅有一棵子树与之相连,选择将其填u if(rnd[lc]>rnd[rc]) rotate(u,0);//若有两棵子树,先旋转处理优先级,再删除 else rotate(u,1); return remove(u,val); } int d=key[u]<val; if(!remove(ch[u][d],val)) return false; return --sz[u],true; } int find_rnk(int val)//根据key求rank,注意先计算rnk,再更新u { int u=root,rnk=1; while(u) { if(val<key[u]) u=lc;//val小于根key值,走lc else if(val>key[u]) rnk+=sz[lc]+cnt[u],u=rc;//val大于根key值,走rc else return rnk+sz[lc];//val等于根key值,直接返回 } return 0; } int find_key(int rnk)//根据rank求key { int u=root; while(u) { if(rnk<=sz[lc]) u=lc; else if(rnk>sz[lc]+cnt[u]) rnk-=sz[lc]+cnt[u],u=rc; else return key[u]; } return 0; } int find_pre(int val)//前驱 { int u=root,pre; while(u) { if(key[u]<val) pre=key[u],u=rc; else u=lc; } return pre; } int find_nxt(int val)//后继 { int u=root,nxt; while(u) { if(key[u]>val) nxt=key[u],u=lc; else u=rc; } return nxt; } int main() { int n,op,x,cnt=0; scanf("%d",&n); while(n--) { ++cnt; scanf("%d%d",&op,&x); switch(op) { case 1:insert(root,x);break; case 2:remove(root,x);break; case 3:printf("%d\n",find_rnk(x));break; case 4:printf("%d\n",find_key(x));break; case 5:printf("%d\n",find_pre(x));break; case 6:printf("%d\n",find_nxt(x));break; } } return 0; }
指针版
之后又手贱写了指针版本,容易RE……不过大致还是类似的,主要是非法地址的处理#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn=100000+10; #define lc (u->ch[0]) #define rc (u->ch[1]) struct Node { Node* ch[2]; int key,rnd,sz,cnt; Node(){ch[0]=ch[1]=NULL;sz=cnt=0;} Node(int key,int rnd):key(key),rnd(rnd){} void update() { sz=ch[0]->sz+ch[1]->sz+cnt; } }*root,*null;//引入null来避免访问非法地址 void rotate(Node* &u,int d)//旋转,d 0,left;1,right. { Node* v=u->ch[d^1]; u->ch[d^1]=v->ch[d]; v->ch[d]=u; u->update(); (u=v)->update(); } void insert(Node* &u,int val) { if(!u||u==null) {//root不要和null赋成一样的,避免null中的sz不为0 u=new Node(val,rand()); u->sz=u->cnt=1; lc=rc=null; return ; } if(val==(u->key)) {++(u->sz),++(u->cnt);return ;} int d=(u->key)<val; insert(u->ch[d],val);++(u->sz); if((u->rnd)>(u->ch[d]->rnd)) rotate(u,d^1); } bool remove(Node* &u,int val) { if(u==null) return false; if((u->key)==val) { Node* t=u; if(u->cnt>1) return --(u->sz),--(u->cnt),true; if(lc==null||rc==null) return u=(lc!=null?lc:rc),delete t,true; if((lc->rnd)>(rc->rnd)) rotate(u,0); else rotate(u,1); return remove(u,val); } int d=(u->key)<val; if(!remove(u->ch[d],val)) return false; return --(u->sz),true; } int find_rnk(int val) { int rnk=1; Node* u=root; while(u!=null) { if(val<(u->key)) u=lc; else if(val>(u->key)) rnk+=(lc->sz)+(u->cnt),u=rc; else return rnk+(lc->sz); } return rnk; } int find_key(int rnk) { Node* u=root; while(u!=null) { if(rnk<=(lc->sz)) u=lc; else if(rnk>(lc->sz)+(u->cnt)) rnk-=(lc->sz)+(u->cnt),u=rc; else return u->key; } return 0; } int find_pre(int val) { int pre; Node* u=root; while(u!=null) { if(val>(u->key)) pre=(u->key),u=rc; else u=lc; } return pre; } int find_nxt(int val) { int nxt; Node* u=root; while(u!=null) { if(val<(u->key)) nxt=(u->key),u=lc; else u=rc; } return nxt; } int main() { null=new Node();//null赋一个地址,不然也会RE null->ch[0]=null->ch[1]=null;//将null的左右儿子也赋成null int n,op,x,cnt=0; scanf("%d",&n); while(n--) { ++cnt; scanf("%d%d",&op,&x); switch(op) { case 1:insert(root,x);break; case 2:remove(root,x);break; case 3:printf("%d\n",find_rnk(x));break; case 4:printf("%d\n",find_key(x));break; case 5:printf("%d\n",find_pre(x));break; case 6:printf("%d\n",find_nxt(x));break; } } return 0; }
相关文章推荐
- 【treap】【bzoj 3224】: Tyvj 1728 普通平衡树
- 【模板】【bzoj3224】Tyvj 1728 普通平衡树 Treap
- Treap模板 BZOJ 3224: Tyvj 1728 普通平衡树
- bzoj3224 Tyvj 1728 普通平衡树(splay/treap)
- [BZOJ3224]Tyvj 1728 普通平衡树 && treap
- 【Treap】[BZOJ 3224]Tyvj 1728 普通平衡树 & 非旋转实现
- 【bzoj3224】Tyvj 1728 普通平衡树 01Trie姿势+平衡树的四种姿势 :splay,旋转Treap,非旋转Treap,替罪羊树
- Treap树堆(bzoj 3224: Tyvj 1728 普通平衡树)
- bzoj3224 Tyvj 1728 普通平衡树 treap
- BZOJ 3224: Tyvj 1728 普通平衡树 treap
- BZOJ 3224 TYVJ 1728 普通平衡树 [Treap树模板]
- bzoj3224Tyvj 1728 普通平衡树 treap
- (treap)[bzoj3224][洛谷3369][cogs1829]Tyvj 1728 普通平衡树
- 【Treap】[BZOJ 3224]Tyvj 1728 普通平衡树
- bzoj3224 Tyvj 1728 普通平衡树 非旋转式Treap
- BZOJ3224 Tyvj 1728 普通平衡树(Treap)
- bzoj 3224: Tyvj 1728 普通平衡树 treap
- BZOJ-3224 普通平衡树 TYVJ-1728 Treap + Vector
- BZOJ3224[Tyvj 1728 普通平衡树]题解--Treap
- BZOJ 3224: Tyvj 1728 普通平衡树 treap