(二叉)堆

堆可以看成一个近似的完全二叉树,其任何一非叶节点满足性质:

Key[i]<=key[2i+1]&&Key[i]<=key[2i+2](小根堆)

或者

Key[i]>=Key[2i+1]&&key[i]>=key[2i+2](大根堆)

有了上面的定义,就有下面的计算:

#define Pa(i) i>>1 //父亲
#define Le(i) i<<1 //左儿子
#define Ri(i) (i<<1)+1 //右儿子
接下来是维护堆的性质:
一个新的i到堆中。(大根堆)
void Mh( int i){
     int l=Le(i),r=Ri(i),lag;
     if (l<=num && heap[i]<heap[l]) lag=l;
     else lag=i;
     if (r<=num && heap[lag]<heap[r]) lag=r;
     if (lag!=i) {
         swap(heap[i],heap[lag]);
         Mh(lag);
     }
}
实现插入操作:
void Hik( int i, int key){
     heap[i]=key;
     while (i>1 && heap[Pa(i)].d<heap[i].d){
         swap(heap[Pa(i)],heap[i]);
         i=Pa(i);
     }
}
删除最大值:
void Hem(){
     if (num<1) {
         printf ( "none\n" ); return ;
     }  
     heap[1]=heap[num];
     num--; Mh(1);
     return ;
}
这些是最基本的堆操作,其他操作可以根据这些推出。
但我们一般不手写,因为STL中有priority_queue。
priority_queue<int>que;默认大根堆。
priority_queue<int, vector<int>, greater<int>> que; 小根堆。(#include<functional>//需要用到greater)
struct cmp{

bool operator()(int x, int y){
return x > y; //x越小优先级越高
}
};
priority_queue<int, vector<int>, cmp>que;//这个声明要特别注意两点:vector<int>和cmp

struct node{
int x, y;
friend bool operator<(node a, node b){//标准库默认使用 < 来确认它们的关系,换成>就不行了哦
return a.y>b.y;//>表示越小越优先,<表示越大越优先
} //可以这样记:最大堆与小于号有关,最小堆与大于号有关。这样记会不会好一点呢。。。
};
priority_queue<node> que;

操作:

que.push();

que.top();

que.pop();

还有映射堆:

两个堆互相标记:

来个题吧:

小明的账单

时间限制: 1 Sec  内存限制: 128 MB

题目描述

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

 

输入

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

 

输出

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

 

样例输入

4
3 3 6 5
2 8 2
3 7 1 7
0

样例输出

3 6
2 8
1 7
5 7
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Pa(i) i>>1
 8 #define Le(i) i<<1
 9 #define Ri(i) (i<<1)+1
10 #define oo 1000000000
11 int size1,size2;
12 struct node{
13     int d,t;
14 } heap_max[2000000],heap_min[2000000];
15 void Max_h(int i){
16     int l=Le(i),r=Ri(i),lag;
17     if (l<=size1 && heap_max[i].d<heap_max[l].d) lag=l;
18     else lag=i;
19     if (r<=size1 && heap_max[lag].d<heap_max[r].d) lag=r;
20     if (lag!=i) {
21         heap_min[heap_max[i].t].t=lag;
22         swap(heap_max[i],heap_max[lag]);
23         return Max_h(lag);
24     } 
25 }
26 void Min_h(int i){
27     int l=Le(i),r=Ri(i),lag;
28     if (l<=size2 && heap_min[i].d>heap_min[l].d) lag=l;
29     else lag=i;
30     if (r<=size2 && heap_min[lag].d>heap_min[r].d) lag=r;
31     if (lag!=i) {
32         heap_max[heap_min[i].t].t=lag;
33         swap(heap_min[i],heap_min[lag]);
34         return Min_h(lag);
35     } 
36 }
37 void Hik_max(int i,int key){
38     heap_max[i].d=key;
39     while (i>1 && heap_max[Pa(i)].d<heap_max[i].d){
40         heap_min[heap_max[i].t].t=Pa(i);
41         swap(heap_max[Pa(i)],heap_max[i]); 
42         i=Pa(i);
43     }
44 }
45 void Hik_min(int i,int key){
46     heap_min[i].d=key;
47     while (i>1 && heap_min[Pa(i)].d>heap_min[i].d){
48         heap_max[heap_min[i].t].t=Pa(i);
49         swap(heap_min[Pa(i)],heap_min[i]); 
50         i=Pa(i);
51     }
52 }
53 void Mhi(int a){
54     size1++; heap_max[size1].d=-oo; heap_max[size1].t=size2+1;
55     size2++; heap_min[size2].d=oo; heap_min[size2].t=size1;
56     Hik_max(size1,a); Hik_min(size2,a);
57 }
58 void Hem(){
59     printf("%d %d\n",heap_min[1].d,heap_max[1].d);
60     int mint=heap_max[1].t,maxt=heap_min[1].t;
61     heap_min[mint]=heap_min[size2];
62     size2--; Min_h(1);
63     heap_max[maxt]=heap_max[size1];
64     size1--; Max_h(1);
65     heap_min[1]=heap_min[size2];
66     size2--; Min_h(1);
67     heap_max[1]=heap_max[size1];
68     size1--; Max_h(1);
69     return;
70 }
71 int main()
72 {
73     int n; scanf("%d",&n);
74     while (n--){
75         int nu; scanf("%d",&nu);
76         for (int i=1;i<=nu;i++) {
77             int a; scanf("%d",&a);
78             Mhi(a);
79         } 
80         Hem();
81     }
82 }
View Code

 

 

 
 

转载于:https://www.cnblogs.com/SXia/p/6930288.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值