Time Limit: 3000MS |
|
Memory Limit: 3000K |
Total Submissions: 57 |
|
Accepted: 21 |
题解:
第一眼看,不就是大根小根两个堆嘛。
但是后来发现有点特殊:每次取完最大和最小的后,要删除它们。
那么明显原来的方法有不足:大根堆去掉最大的,小根堆里去不掉这个元素。
那么后来我想到:1.直接坑上厉害数据结构
2.映射。
明显第2种打起来简单多了。一开始自己完完全全想太多。
映射是什么意思?映射是很好的东西,包括dij+堆一些和堆有关的总可以用上。
举个例子:
minheap={3,6,5}
maxheap={6,5,3}
设立两个数组mintomax和maxtomin,mintomax[i]表示minheap[i]所对应的maxheap里的元素位置,
maxtomin[i]表示maxheap[i]所对应的minheap里的元素位置。
那么在上述例子中:
mintomax={3,1,2}
maxtomin={2,3,1}
这样子,如果minheap里取了3,那么maxheap里就可以确定位置来去掉3了。
可能有个疑问:怎么在堆里去掉任意一个元素?
很明显,如果堆的位置x的元素去掉,把堆看做完全二叉树,
只要将最后一个元素放到x位置,然后整理以x为根的树就好了。
那么设立一个down(y)整理以y为根的树,就可以处理了。
贴上Pascal代码。
var n,m,i,j,x,min,max,hlen,hlen1:longint;
mintomax,maxtomin,mh,ah:array[0..2000001] of longint;
procedure swap(var a,b:longint);
var t:longint;
begin
t:=a; a:=b; b:=t;
end;
procedure putmin(x:longint);
var i:longint;
begin
mh[hlen]:=x;
i:=hlen;
while (i>1)and(mh[i>>1]>mh[i]) do
begin
swap(mh[i>>1],mh[i]);
swap(maxtomin[mintomax[i>>1]],maxtomin[mintomax[i]]);
swap(mintomax[i>>1],mintomax[i]);
i:=i>>1;
end;
end;
procedure putmax(x:longint);
var i:longint;
begin
ah[hlen1]:=x;
i:=hlen1;
while (i>1)and(ah[i>>1]>1],ah[i]);
swap(mintomax[maxtomin[i>>1]],mintomax[maxtomin[i]]);
swap(maxtomin[i>>1],maxtomin[i]);
i:=i>>1;
end;
end;
procedure delmax(x:longint);
var i,l,r,lar:longint;
begin
swap(ah[hlen1],ah[x]);
swap(mintomax[maxtomin[hlen1]],mintomax[maxtomin[x]]);
swap(maxtomin[hlen1],maxtomin[x]);
dec(hlen1);
i:=x;
while (i<=hlen1) do
begin
l:=i<<1;
r:=i<<1+1;
if (l<=hlen1)and(ah[l]>ah[i]) then
lar:=l else lar:=i;
if (r<=hlen1)and(ah[r]>ah[lar]) then
lar:=r;
if i=lar then exit;
swap(ah[i],ah[lar]);
swap(mintomax[maxtomin[lar]],mintomax[maxtomin[i]]);
swap(maxtomin[i],maxtomin[lar]);
i:=lar;
end;
end;
procedure delmin(x:longint);
var i,l,r,sma:longint;
begin
swap(mh[hlen],mh[x]);
swap(maxtomin[mintomax[hlen]],maxtomin[mintomax[x]]);
swap(mintomax[hlen],mintomax[x]);
dec(hlen);
i:=x;
while (i<=hlen) do
begin
l:=i<<1;
r:=i<<1+1;
if (l<=hlen)and(mh[l]