题意:给定M个数,每次可以插入序列一个数;再给N个数,表示在插入第几个数时输出一个数,第一次输出序列中最小的,第二次输出序列中第二小的……以此类推,直到输出N个数
分析:先记录下要插入的节点,另开一个数组记录要查询的状态。用treap维护,每个节点维护一个子节点的总数sum,查询的时候只要按照sum值进行查询就可以了,注意insert和rotate的时候更新节点的sum。
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
struct node
{
int r,v,sum;
node *ch[2];
node(int v):v(v){
ch[0] = ch[1] = NULL; r= rand();
sum = 1;
}
bool operator < (const node &tr) const
{
return r >tr.r;
}
int cmp(int x) const
{
if(v == x) return -1;
else return v < x ? 0:1 ;
}
};
node *root;
void pushup(node* &o)
{
o->sum = 1;
if(o->ch[0] != NULL) o->sum += o->ch[0]->sum;
if(o->ch[1] != NULL) o->sum += o->ch[1]->sum;
}
void rotate(node* &o, int d)
{
node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d];k ->ch[d] = o;
pushup(o);
pushup(k);
if(o == root) root = k;
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);
pushup(o);
if(o->ch[d]->r > o->r) rotate(o,d^1);
}
}
int find(node* o,int x)
{
if(o->ch[0] == NULL && x == 1) return o->v;
if(o->ch[0] != NULL &&o->ch[0]->sum == x - 1) return o->v;
if(o->ch[0] != NULL && o->ch[0]->sum > x -1) return find(o->ch[0],x);
else
{
x -= 1;
if(o->ch[0] != NULL) x -= o->ch[0]->sum;
return find(o->ch[1],x);
}
}
int a[30000+5];
int ge[30000+5];
int main()
{
int n,q;
root =NULL;
scanf("%d%d",&n,&q);
for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
for(int i = 1; i <= q; i++ ) scanf("%d",&ge[i]);
int id = 1;
for(int i =1; i <= n; i++)
{
insert(root,a[i]);
while(i == ge[id])
{
int x = find(root,id++);
printf("%d\n",x);
}
}
}