Uva 11136 - Hoax or what 这道题可以用优先队列做,这里讨论一下用最小-最大堆做。
题目的要求:需要找到最小值和最大值,并且还有删除最小值和最大值。
这样就需要一种包括下面几种操作的数据结构:
- insert 插入一个元
- get_min() 得到最小元素,并将其从集合中删除
- get_max()的到最大元素,并将其从集合中删除
如果只是需要找到最小值或者最大值,那么可以用heap,也可以用优先队列。但是这里需要找到最小值和最大值,还是可以用heap,也就是双端堆/最小-最大堆/Double-Ended Heap 。
查询效率为常数,删除效率为O(log(n))
下面附上一篇论文: http://pan.baidu.com/share/link?shareid=1020027175&uk=70243437
所谓的最小-最大堆,就是在一个二叉树中同时维护两个堆(最小堆和最大堆)的性质。最开始的最小-最大堆是最小堆和最大堆一次按照二叉树树深交替出现,但是这里的最小-最大堆是左子树为最小堆,右子树为最大堆,且左兄弟不能大于右兄弟。
论文只讲了如何插入元素,因为删除最大元素和最小元素和普通的heap操作差不多。在删除操作中充分利用最小-最大堆的限制就可以很轻松的写出代码。下面的代码不知道正确否,因为在Uva上提交时显示提交错误,换了几个号都是,求解释啊。
/*最小-最大堆的实现
不断的维护这样一个二叉树:左子树为最小堆,右子树为最大堆
有三个操作:
插入 插入的同时维护最小-最大堆的性质
返回最大值 返回的同时删除最大值,并维护最小-最大堆的性质
返回最小值 返回的同时删除最小值,并维护最小-最大堆的性质
*/
#include <stdio.h>
#include <string.h>
#define maxn 100100
struct heap
{
int len;
int a[maxn];
void init()
{
len = 0;
memset(a,0,sizeof(0));
}
void heap_insert(int x)
{
int p = ++len;
int gf;
int l,r;
while(1)
{
if(!(p&1) && a[p-1] > x)
{
a[p] = a[p-1];
p--;
}
gf = ((p+1) >> 2)-1;
if(gf < 0) break;
if(gf == 0) l = 1,r = 2;
else l = (gf<<1) +1,r = l + 1;
if(x < a[l]) a[p] =a[l],p = l;
else if(x > a[r]) a[p] = a[r],p = r;
else break;
}
a[p] = x;
}
int get_min()
{
int p = 1;
int Min = a[p];
int temp;
a[p] = a[len--];
while(1)
{
if((p&1) && p+1 <= len && a[p] > a[p+1])
{
temp = a[p+1];
a[p+1] = a[p];
a[p] = temp;
}
int lchild = (p<<1) + 1;
if(lchild > len) break;
if(a[p] > a[lchild])
{
temp = a[p];
a[p] = a[lchild];
a[lchild] = temp;
}
else break;
}
return Min;
}
int get_max()
{
int p = 2;
int Max = a[p];
int temp;
a[p] = a[len--];
while(1)
{
if(!(p&1) && p-1 >= 1 && a[p] < a[p-1])
{
temp = a[p];
a[p] = a[p-1];
a[p-1] = a[p];
}
int rchild = (p<<1)+2;
if(rchild > len) break;
if(a[p] < a[rchild])
{
temp = a[rchild];
a[rchild] = a[p];
a[p] = a[rchild];
}
else break;
}
return Max;
}
} h;
int ans;
int n,m;
int main()
{
while(scanf("%d",&n) && n)
{
h.init();
ans = 0;
while(n--)
{
scanf("%d",&m);
int x;
while(m--)
{
scanf("%d",&x);
h.heap_insert(x);
}
int Max = h.get_max();
int Min = h.get_min();
ans += Max - Min;
}
printf("%d\n",ans);
}
return 0;
}