题目描述
您需要写一种数据结构,来维护一些数( 都是 10^9 以内的数字)的集合,最开始时集合是空的。其中需要提供以下操作,操作次数 q 不超过 10^4:
- 查询 x 数的排名(排名定义为比当前数小的数的个数 +1。若有多个相同的数,因输出最小的排名)。
- 查询排名为 x的数。
- 求 x 的前驱(前驱定义为小于 x,且最大的数)。
- 求 x 的后继(后继定义为大于 x,且最小的数)。
- 插入一个数 x。
输入输出样例
输入
7
5 1 5 3 5 5 1 3 2 2 3 3 4 3
输出
2 3 1 5
什么是二叉树?
每个结点最多有两个子结点,分别称为左孩子,右孩子,以他们为根的树称为左子树,右子树。
1 struct node{ 2 int val; 3 node* l,r; 4 };
什么是BST(Binary Search Tree)?
(1)每个元素有唯一的键值。这些键值能比较大小。
(2)任意一个结点的键值比它的左子树的任意结点大,右子树的任意结点小。
所以我们使用中序遍历就可以得到BST的有序排列。
如图就是一个BST。
BST的基本操作有:插入,查询,删除。
根据题意,我们只需要实现插入,和查询的操作。
题目有些东西没讲清楚,比如:
(1)查询x数的排名时 x可能不在树上
(2)没有前驱输出-0X7fffffff
(3)没有后继输出 0X7fffffff
指针实现的变种BST(有多个相同键值,后来插入的相同键值被安插在了第一个相同键值的左子树上)代码:
#include<bits/stdc++.h> using namespace std; //使用BST,二叉搜索树 struct node { node *l, *r; int v,lsum,rsum; node(int val):v(val),lsum(0),rsum(0),l(0),r(0){} } *root; void insert(node*& now,int x) {//*&表示在函数里面对now的值进行改变,那么在调用函数时传入的参数的指针值也会改变 if (!now) { now = new node(x); return; } if (now->v <= x) insert(now->r, x),now->rsum++; else insert(now->l, x), now->lsum++; } int find_rank(node* now,int x,int k) { if(!now) return k; if (now->v == x)return k + now->lsum + 1; if (now->v < x)return find_rank(now->r, x, k + now->lsum+1); return find_rank(now->l, x, k); } int find_num(node* now,int x) { if (!now)return 2147483647; int tmp = now->lsum + 1; if (tmp == x)return now->v; if (tmp < x)return find_num(now->r, x - tmp); return find_num(now->l, x); } int prev_num(int x) { node* p = root; int c=-2147483647; while (p) { if (x > (p->v)) { c = p->v; p = p->r; } else { p = p->l; } } return c; } int next_num(int x) { node* p = root; int c = 2147483647; while (p) { if (x < (p->v)) { c = p->v; p = p->l; } else { p = p->r; } } return c; } int main() { int n,a,b; cin >> n; while (n--) { cin >> a >> b; switch (a) { case 5:insert(root,b); break; case 1:cout<<find_rank(root,b,0)<<endl; break; case 2:cout<<find_num(root,b)<<endl; break; case 3:cout << prev_num(b) << endl; break; case 4:cout << next_num(b) << endl; break; } } return 0; }
(这个过样例的时候是可以的,但在提交的时候莫名其妙要把cout<<find_rank(root,b,0)<<endl;改为cout<<find_rank(root,b,0)+1<<endl;,然后样例就过不了了,结果AC了。呕血~)
然后是数组实现代码。
#include<iostream> #include<cstdio> using namespace std; const int INF=0x7fffffff; int cont; struct node{ int val,ls,rs,cnt,siz; }tree[500010]; int n,opt,xx; void add(int x,int v) { tree[x].siz++; if(tree[x].val==v){ tree[x].cnt++; return ; } if(tree[x].val>v){ if(tree[x].ls!=0) add(tree[x].ls,v); else{ cont++; tree[cont].val=v; tree[cont].siz=tree[cont].cnt=1; tree[x].ls=cont; } } else{ if(tree[x].rs!=0) add(tree[x].rs,v); else{ cont++; tree[cont].val=v; tree[cont].siz=tree[cont].cnt=1; tree[x].rs=cont; } } } int queryfr(int x, int val, int ans) { if (tree[x].val>=val) { if (tree[x].ls==0) return ans; else queryfr(tree[x].ls,val,ans); } else { if (tree[x].rs==0) return (tree[x].val<val) ? tree[x].val : ans; if (tree[x].cnt!=0) return queryfr(tree[x].rs,val,tree[x].val); else return queryfr(tree[x].rs,val,ans); } } int queryne(int x, int val, int ans) { if (tree[x].val<=val) { if (tree[x].rs==0) return ans; else queryne(tree[x].rs,val,ans); } else { if (tree[x].ls==0) return (tree[x].val>val)? tree[x].val : ans; if (tree[x].cnt!=0) return queryne(tree[x].ls,val,tree[x].val); else return queryne(tree[x].ls,val,ans); } } int queryrk(int x,int rk) { if(x==0) return INF; if(tree[tree[x].ls].siz>=rk) return queryrk(tree[x].ls,rk); if(tree[tree[x].ls].siz+tree[x].cnt>=rk) return tree[x].val; return queryrk(tree[x].rs,rk-tree[tree[x].ls].siz-tree[x].cnt); } int queryval(int x,int val) { if(x==0) return 0; if(val==tree[x].val) return tree[tree[x].ls].siz+1; if(val<tree[x].val) return queryval(tree[x].ls,val); return queryval(tree[x].rs,val)+tree[tree[x].ls].siz+tree[x].cnt; } inline int read() { int r=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ r=(r<<3)+(r<<1)+(ch^48); ch=getchar(); } return r*w; } int main() { n=read(); while(n--){ opt=read();xx=read(); if(opt==1) printf("%d ",queryval(1,xx)+1); else if(opt==2) printf("%d ",queryrk(1,xx)); else if(opt==3) printf("%d ",queryfr(1,xx,-INF)); else if(opt==4) printf("%d ",queryne(1,xx,INF)); else{ if(cont==0){ cont++; tree[cont].cnt=tree[cont].siz=1; tree[cont].val=xx; } else add(1,xx); } } return 0; }