一、二叉堆性质:
1.数据结构是一颗完全二叉树
2.任意一个节点小于父节点称为”大根堆“,任意节点小于父节点称为”小根堆"
二、使用数组实现的小根堆二叉堆操作:
1.向上调整:
此时该节点不满足二叉堆性质,则通过与父节点交换来满足二叉堆性质,然后调整父节点,不断向上调整,使其满足性质为止.
void Up(int v)
{
while(v>1)
{
if(a[v/2]>a[v])
{
swap(a[v/2],a[v]);
v=v/2;
}
else
{
return ;
}
}
}
2.向下调整:
此时该节点不满足二叉堆性质,则通过与子节点交换来满足二叉堆性质,然后调整子节点,不断向下调整,使其满足性质为止.
void Down(int v)
{
while(v*2<ji)
{
int k=v*2, val=a[v*2];
if(v*2+1<ji&&a[v*2+1]<val)
{
k=v*2+1;
val=a[v*2+1];
}
if(a[v]>val)
{
swap(a[v],a[k]);
v=k;
}
else
{
return ;
}
}
}
3.插入:
向二叉堆插入一个节点时将该节点插入到末尾,然后向上调整。
void Add(int x)
{
a[ji++]=x;
Up(ji-1);
}
4.删除根节点
void Remove()
{
ji--;
a[1]=a[ji];
Down(1);
}
三、题目
题目一:Supermarket(poj1456)
题意:
思路:
每个商品按过期时间升序排列,然后用小根堆维护,大小最大为当前时间,最后还在堆中的值的和为结果.
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inf=2e18;
int ji=1, a[1000005];
struct w
{
int p, t;
} w[1000005];
bool cmp(struct w a,struct w b)
{
return a.t<b.t;
}
void Down(int v)
{
while(v*2<ji)
{
int k=v*2, val=a[v*2];
if(v*2+1<ji&&a[v*2+1]<val)
{
k=v*2+1;
val=a[v*2+1];
}
if(a[v]>val)
{
swap(a[v],a[k]);
v=k;
}
else
{
return ;
}
}
}
void Up(int v)
{
while(v>1)
{
if(a[v/2]>a[v])
{
swap(a[v/2],a[v]);
v=v/2;
}
else
{
return ;
}
}
}
void Remove()
{
ji--;
a[1]=a[ji];
Down(1);
}
void Add(int x)
{
a[ji++]=x;
Up(ji-1);
}
int main()
{
int n;
while(~scanf("%d",&n))
{
ji=1;
for(int i=1; i<=n; i++)
scanf("%d%d",&w[i].p,&w[i].t);
sort(w+1,w+n+1,cmp);
int o=1,i=1;
for(; i<=n&&o<=n; o++)
{
while(i<=n&&w[i].t<=o)
{
if(ji<=o||w[i].p>a[1])
{
if(ji>o)
{
Remove();
Add(w[i].p);
}
else
{
Add(w[i].p);
}
}
i++;
}
}
while(o>n&&i<=n)
{
if(ji<=n||w[i].p>a[1])
{
if(ji>n)
{
Remove();
Add(w[i].p);
}
else
{
Add(w[i].p);
}
}
i++;
}
ll ans=0;
//printf("%d\n",ji);
for(int i=1; i<ji; i++)
{
ans=ans+a[i];
}
cout << ans << endl;
}
}
题目二:Sequence(poj2442)
题目:
思路:用大根堆维护最小的n个数,按行操作.
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inf=2e18;
ll ji=1, a[1000005], b[1000005], c[1000005];
void Down(int v)
{
while(v*2<ji)
{
int k=v*2, val=a[v*2];
if(v*2+1<ji&&a[v*2+1]>val)
{
k=v*2+1;
val=a[v*2+1];
}
if(a[v]<val)
{
swap(a[v],a[k]);
v=k;
}
else
{
return ;
}
}
}
void Up(int v)
{
while(v>1)
{
if(a[v/2]<a[v])
{
swap(a[v/2],a[v]);
v=v/2;
}
else
{
return ;
}
}
}
void Remove()
{
ji--;
a[1]=a[ji];
Down(1);
}
void Add(int x)
{
a[ji++]=x;
Up(ji-1);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n, m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf("%lld",&b[j]);
}
if(i==1)
{
ji=1;
for(int j=1; j<=m; j++)
{
Add(b[j]);
}
}
else
{
for(int j=1; j<=m; j++)
{
c[j]=a[j];
}
ji=1;
for(int j=1; j<=m; j++)
{
for(int o=1; o<=m; o++)
{
if(ji<=m||a[1]>b[j]+c[o])
{
if(ji>m)
{
Remove();
}
//printf("%lld\n",b[j]+c[o]);
Add(b[j]+c[o]);
}
}
}
}
}
sort(a+1,a+ji);
for(int i=1; i<ji; i++)
{
printf("%lld%c",a[i],i+1==ji?'\n':' ');
}
}
}
题目三:数据备份(Acwing147)
题目:
思路:双向链表加小根堆,可反悔堆.
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inf=1e9+7;
int s[100005];
int head=-1, pre[200005], Next[200005], val[200005], ji=1;
struct w
{
int v, val;
} w, w2;
bool operator < (struct w a,struct w b)
{
return a.val>b.val;
}
int main()
{
int n, k;
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++)
{
scanf("%d",&s[i]);
}
for(int i=2; i<=n; i++)
{
val[ji]=s[i]-s[i-1];
pre[ji]=-1;
Next[ji]=head;
if(head!=-1)
pre[head]=ji;
head=ji;
ji++;
}
priority_queue<struct w> q;
ll ans=0;
for(int i=head; i!=-1; i=Next[i])
{
w.v=i;
w.val=val[i];
q.push(w);
}
while(k--)
{
w.v=-1;
while(w.v==-1||val[w.v]==-1)
{
w=q.top();
q.pop();
}
ans+=w.val;
//printf("%d %d\n",w.v,ans);
if(pre[w.v]!=-1&&Next[w.v]!=-1)
{
w2.v=ji;
w2.val=val[pre[w.v]]+val[Next[w.v]]-val[w.v];
val[ji]=w2.val;
val[pre[w.v]]=-1;
val[Next[w.v]]=-1;
pre[ji]=pre[pre[w.v]];
if(pre[pre[w.v]]==-1)
{
head=ji;
}
else
{
Next[pre[pre[w.v]]]=ji;
}
Next[ji]=Next[Next[w.v]];
if(Next[Next[w.v]]!=-1)
{
pre[Next[Next[w.v]]]=ji;
}
ji++;
q.push(w2);
}
else if(pre[w.v]==-1&&Next[w.v]!=-1)
{
val[Next[w.v]]=-1;
head=Next[Next[w.v]];
if(Next[Next[w.v]]!=-1)
{
pre[Next[Next[w.v]]]=-1;
}
}
else if(pre[w.v]!=-1&&Next[w.v]==-1)
{
val[pre[w.v]]=-1;
if(pre[pre[w.v]]==-1)
{
head=-1;
}
else
{
Next[pre[pre[w.v]]]=-1;
}
}
else
{
head=-1;
}
}
cout << ans << endl;
}