题意:
给定一个数组,有两种操作:
A x :表示插入x。
Get i:表示返回第i小的数。
题解:
Treap实现名次树。
然而这道题出的比较特殊,这一个数组顺序,连续插入一段,然后输出第i大,i从1到n依次增大。可以用两个优先队列去写。
Treap实现:
#include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #include<cstring> using namespace std; struct node { node *ch[2]; int r,v,s; node(int v):v(v) { s=1; ch[0]=ch[1]=NULL; r=rand(); } bool operator < (const node& a)const { return r<a.r; } int cmp(int x) { if(x==v)return -1; return x<v?0:1; } void maintain() { s=1; if(ch[0]!=NULL) s+=ch[0]->s; if(ch[1]!=NULL) s+=ch[1]->s; } }; void Rotate(node* &o,int d) { node *k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void Insert(node* &o,int x) { if(o==NULL)o=new node(x); else { int d = x<(o->v)?0:1; Insert(o->ch[d],x); if(o->ch[d]->r > o->r) Rotate(o,d^1); } o->maintain(); } int kth(node *o,int k)//第k小的值 { int s = (o->ch[0]==NULL)?0:o->ch[0]->s; if(k==s+1)return o->v; if(k<s+1)return kth(o->ch[0],k); return kth(o->ch[1],k-s-1); } const int maxn=30011; int m,n; int a[maxn],g; int main() { srand(100); node* root = NULL; scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) scanf("%d",a+i); int j=1; for(int i=1;i<=n;i++) { scanf("%d",&g); for(;j<=g;j++) Insert(root,a[j]); printf("%d\n",kth(root,i)); } }
两个优先队列实现:
#include<cstdio> #include<queue> using namespace std; priority_queue<int >pq1; priority_queue<int,vector<int>,greater<int> >pq2; int a[33333]; int main() { int n,m,x; scanf("%d%d",&n,&m); int k = 1; for(int i=1;i<=n;i++)scanf("%d",a+i); for(int i=1;i<=m;i++) { scanf("%d",&x); while(k<=x) { pq2.push(a[k]); if(pq1.size() && pq1.top() > pq2.top()) { int tmp = pq1.top();pq1.pop();pq2.push(tmp); tmp = pq2.top();pq2.pop();pq1.push(tmp); } k++; } printf("%d\n",pq2.top()); int tmp = pq2.top();pq2.pop();pq1.push(tmp); } }