开始学习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;
}
}