poj 1442 treap

题意:给定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);
        }
    }
}


猜你喜欢

转载自blog.csdn.net/zlatan10/article/details/77113770