题目大意
给你一些数,你可以选着按顺序插入,和查找第k大的数是哪个,每次查找输出低k大的数
思路:
一个大根堆加一个小根堆…
或者是用平衡树或者是权值线段树…
抱歉我是口头ac,啊哈哈哈。
我的方法是离线做的,你把每次操作都给保存下来,先用所有的数去造一棵树,每次插入就变成删除,然后用数组存每次的查找结果,最后反正输出。
程序:
uses
math;
const
maxn=1000000;
var
s,a,b,f,big,c,d:array [0..maxn] of longint;
i,j,n,m,hjy:longint;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l; j:=r;
mid:=a[(l+r) div 2];
while i<j do
begin
while a[i]<mid do inc(i);
while a[j]>mid do dec(j);
if i<=j then
begin
a[0]:=a[i];
a[i]:=a[j];
a[j]:=a[0];
inc(i); dec(j);
end;
end;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
procedure make(l,r,o:longint);
var
i,j,mid:longint;
begin
if l=r then
begin
f[o]:=a[l];
s[o]:=1;
big[o]:=a[l];
exit;
end;
mid:=(l+r) div 2;
make(l,mid,o*2);
make(mid+1,r,o*2+1);
s[o]:=s[o*2]+s[o*2+1];
big[o]:=max(big[o*2],big[o*2+1]);
end;
procedure find(l,r,x,o,t:longint);
var
i,j,mid:longint;
begin
if l=r then
begin
inc(hjy);
d[hjy]:=f[o];
exit;
end;
mid:=(l+r) div 2;
if s[o*2]+t>=x then find(l,mid,x,o*2,t)
else find(mid+1,r,x,o*2+1,t+s[o*2]);
end;
procedure delete(l,r,x,o:longint);
var
i,j,mid:longint;
begin
if l=r then
begin
f[o]:=0;
s[o]:=0;
big[o]:=-maxlongint;
exit;
end;
mid:=(l+r) div 2;
if big[o*2]>=x then delete(l,mid,x,o*2)
else delete(mid+1,r,x,o*2+1);
s[o]:=s[o*2]+s[o*2+1];
big[o]:=max(big[o*2],big[o*2+1]);
end;
begin
readln(n,m);
for i:=1 to n do
read(a[i]);
c:=a;
readln;
for i:=1 to m do
read(b[i]);
for i:=0 to maxn do
big[i]:=-maxlongint;
qsort(1,n);
make(1,n,1);
j:=m;
for i:=n downto 1 do
begin
while b[j]=i do
begin
find(1,n,j,1,0);
dec(j);
end;
delete(1,n,c[i],1);
end;
for i:=hjy downto 1 do
writeln(d[i]);
end.