【zjnu1248】小明的账单(bill) 堆的应用

小明的账单——高级

Time Limit: 3000MS

 

Memory Limit: 3000K

Total Submissions: 57

 

Accepted: 21

Description

小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单。。。
在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没有支付的账单会被保留到下一天。
请你帮他计算出支付的顺序。

Input

第1 行:一个正整数N(N≤15,000),表示小明补办银联卡总共的天数。
第2 行到第N+1 行:每一行描述一天中收到的帐单。先是一个非负整数M<=100,表示当天
收到的账单数,后跟M个正整数(都小于1,000,000,000),表示每张帐单的面额。
输入数据保证每天都可以支付两张帐单。

Output

输出共N行,每行两个用空格分隔的整数,分别表示当天支付的面额最小和最大的支票的面额。

Sample Input

4

3 3 6 5

2 8 2

3 7 1 7

0

Sample Output

3 6

2 8

1 7

5 7

 

题解:

第一眼看,不就是大根小根两个堆嘛。

但是后来发现有点特殊:每次取完最大和最小的后,要删除它们。

那么明显原来的方法有不足:大根堆去掉最大的,小根堆里去不掉这个元素。

那么后来我想到: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为根的树,就可以处理了。

【zjnu1248】小明的账单(bill) 堆的应用_第1张图片

贴上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]


你可能感兴趣的:((可并)堆)