题目描述
Black Box是一种原始的数据库。它可以储存一个整数数组,还有一个特别的变量
i
。最开始的时候Black Box是空的.而i等于0。这个Black Box要处理一串命令。
命令只有两种:
ADD(
GET:
记住:第
我们来演示一下一个有11个命令的命令串。(如下图所示)
现在要求找出对于给定的命令串的最好的处理方法。ADD和GET命令分别最多
200000
个。现在用两个整数数组来表示命令串:
1.
A(1)
,
A(2)
,…
A(M)
:一串将要被放进Black Box的元素。每个数都是绝对值不超过
2000000000
的整数,
M≤200000
。例如上面的例子就是
A=(3,1,−4,2,8,−1000,2)
。
2.
u(1),u(2),…u(N)
:表示第
u(j)
个元素被放进了Black Box里后就出现一个GET命令。例如上面的例子中
u=(1,2,6,6)
。输入数据不用判错。
输入输出格式
输入格式:
第一行,两个整数,
M
,
第二行,
M
个整数,表示
第三行,
N
个整数,表示
输出格式:
输出Black Box根据命令串所得出的输出串,一个数字一行。
输入输出样例
输入样例#1:
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
输出样例#1:
3
3
1
2
说明
对于
30%
的数据,
M≤10000
;
对于
50%
的数据,
M≤100000
;
对于
100%
的数据,
M≤200000
。
思路
有两种方法:
第一种:强行splay大法,直接按照题目意思在splay上操作。(splay可以换成其他的BST)
第二种:标准方法(堆),既然询问的
k
是递增的,那么可以把前
1. 每加入一个数,先丢到大根堆中,再将大根堆中最大的数取出来丢到小根堆中;
2. 询问第
k
大的数,只需要输出小根堆中的数,然后丢到大根堆中。
3. 正确性?加入的时候,如果加入的数是加入后的数列中前
4. 询问的时候,小根堆中最小的数一定是第
k
大的,而将其取出后由于
代码(splay版)
#include <cstdio>
const int maxn=200000;
struct splay_tree
{
int fa[maxn+10],son[2][maxn+10],val[maxn+10],size[maxn+10],tot,root;
int t(int x)
{
return son[1][fa[x]]==x;
}
int updata(int x)
{
size[x]=1;
if(son[0][x])
{
size[x]+=size[son[0][x]];
}
if(son[1][x])
{
size[x]+=size[son[1][x]];
}
return 0;
}
int rotate(int x)
{
int k=t(x),f=fa[x];
fa[x]=fa[f];
if(fa[f])
{
son[t(f)][fa[f]]=x;
}
son[k][f]=son[!k][x];
if(son[!k][x])
{
fa[son[!k][x]]=f;
}
son[!k][x]=f;
fa[f]=x;
updata(f);
updata(x);
return 0;
}
int splay(int x,int c)
{
while(fa[x]!=c)
{
int f=fa[x];
if(fa[f]==c)
{
rotate(x);
}
else if(t(x)==t(f))
{
rotate(f);
rotate(x);
}
else
{
rotate(x);
rotate(x);
}
}
if(!c)
{
root=x;
}
return 0;
}
int newnode(int x)
{
++tot;
val[tot]=x;
size[tot]=1;
return 0;
}
int ins(int x)
{
newnode(x);
if(!root)
{
root=tot;
fa[tot]=son[0][tot]=son[1][tot]=0;
return 0;
}
int now=root;
while(now)
{
int p=val[now]<x;
if(!son[p][now])
{
son[p][now]=tot;
fa[tot]=now;
son[0][tot]=son[1][tot]=0;
break;
}
now=son[p][now];
}
splay(tot,0);
return 0;
}
int getkth(int x)
{
int now=root;
while(now)
{
if(size[son[0][now]]+1==x)
{
break;
}
else if(size[son[0][now]]+1<x)
{
x-=size[son[0][now]]+1;
now=son[1][now];
}
else
{
now=son[0][now];
}
}
splay(now,0);
return val[now];
}
};
splay_tree st;
int n,m,a[maxn+10],b[maxn+10],now=1;
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; ++i)
{
scanf("%d",&a[i]);
}
for(register int i=1; i<=m; ++i)
{
scanf("%d",&b[i]);
}
for(register int i=1; i<=n; ++i)
{
st.ins(a[i]);
while((now<=m)&&(b[now]==i))
{
printf("%d\n",st.getkth(now));
++now;
}
}
return 0;
}
代码(堆版)
#include <cstdio>
#include <ext/pb_ds/priority_queue.hpp>//pbds神教,速度比STL堆快,支持两堆的合并
const int maxn=200000;
__gnu_pbds::priority_queue<long long,std::greater<long long> > box;//建立一个小根堆
__gnu_pbds::priority_queue<long long> w;//建立一个大根堆
long long sw,m,n,now;
long long a[maxn+10],u[maxn+10];
int main()
{
now=1;
scanf("%lld%lld",&m,&n);
for(int i=1; i<=m; i++)
{
scanf("%lld",&a[i]);
}
for(int i=1; i<=n; i++)
{
scanf("%lld",&u[i]);
}
for(int i=1; i<=m; i++)
{
w.push(a[i]);
box.push(w.top());
w.pop();
while(i==u[now])
{
printf("%lld\n",box.top());
w.push(box.top());
box.pop();
now++;
}
}
return 0;
}