POJ 1442 Black Box Treap

                   开始学习Treap这个结构了,先拿这道题目来练一练手吧!

                   老实说这道题目一开始没怎么把题目看明白。。。后面才明白题目给的两个序列的意思。

                   A(M)这个序列是准备加到Black Box那里面去的元素,也就是add操作,U(n)这个序列代表的是总共执行了多少个add操作之后就执行一个get。

                  样例给的U序列是1,2,6,6,也就是在总共add一次之后执行一个get,然后add总共执行两次之后get一次,然后就是在总共执行6次add之后连续执行两次get。

                  这题目要求我们找到第p小的元素,要使用Treap的话,还需要在每一个节点多储存一个size,来表示它和它的左右子树上的节点个数。

                  模板题

                  Tips:

                  cnt计数。rt代表root,表示根节点。find_rank(int level,int &x)表示查询第level小的节点,返回节点的下标。find_num(int key,int &x)查询值小于等于key的节点的个数,返回个数(此题没用用到)

                  POJ用srand(time(0))会RE。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;

ll cnt=1,rt;
struct Node{
    ll son[2],pri,val,sz;
    void set_size();
    void newnode(ll v){son[0]=son[1]=0;sz=1,pri=rand(),val=v;}
}tree[100010];

void Node::set_size(){
     sz=1+tree[son[0]].sz+tree[son[1]].sz;
}

void rot(bool p,ll &x){
    ll k=tree[x].son[!p];
    tree[x].son[!p]=tree[k].son[p];
    tree[k].son[p]=x;
    tree[x].set_size();
    tree[k].set_size();
    x=k;
}

void ins(ll key,ll &x){
    if(x){
        bool p=key>=tree[x].val;
        //printf("ins:%d %d %d\n",key,tree[x].val,key>=tree[x].val);
        ins(key,tree[x].son[p]);
        if(tree[tree[x].son[p]].pri>tree[x].pri)
            rot(!p,x);
    }
    else
        tree[x=cnt++].newnode(key);
    tree[x].set_size();
}

void del(ll key,ll &x){
    if(key==tree[x].val){
        if(!tree[x].son[0])
            x=tree[x].son[1];
        else if(!tree[x].son[1])
            x=tree[x].son[0];
        else{
            bool p=tree[tree[x].son[0]].pri>tree[tree[x].son[1]].pri;
            rot(p,x);
            del(key,tree[x].son[p]);
        }
    }
    else
        del(key,tree[x].son[key>=tree[x].val]);
    if(x)
        tree[x].set_size();
}

ll find_num(ll key,ll &x){
    if(!x)
        return 0;
    if(tree[x].val>key)
        return find_num(key,tree[x].son[0]);
    else
        return tree[tree[x].son[0]].sz+1+find_num(key,tree[x].son[1]);
}

ll find_rank(ll level,ll &x){
    if(level==tree[tree[x].son[0]].sz+1)
        return x;
    else if(level>tree[tree[x].son[0]].sz+1)
        return find_rank(level-tree[tree[x].son[0]].sz-1,tree[x].son[1]);
    else
        return find_rank(level,tree[x].son[0]);
}

ll m,n,arr[30010],u[30010];

int main(){
    while(scanf("%lld%lld",&m,&n)!=EOF){
        for(int i=1;i<=m;++i)
            scanf("%lld",&arr[i]);
        for(int i=1;i<=n;++i)
            scanf("%lld",&u[i]);
        for(int i=1,j=1;j<=n;++j){
            while(i<=u[j])
                ins(arr[i++],rt);
            if(i==u[j]+1)
                printf("%lld\n",tree[find_rank(j,rt)].val);
        }
        cnt=1,rt=0;
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值