题解:哈夫曼树
先补全节点,以总个数为第一关键字,高度为第二关键字,求哈夫曼树即可
问题:不明白哈夫曼树的原理及证明
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long Lint;
const int maxn=100009;
int n,m;
Lint anssum,ansh;
int nn;
Lint sum[maxn<<2];
Lint h[maxn<<2];
struct Point{
int x;
bool operator < (const Point &rhs) const{
if(sum[x]==sum[rhs.x]){
return h[x]>h[rhs.x];
}else{
return sum[x]>sum[rhs.x];
}
}
Point(int xx){
x=xx;
}
Point(){}
};
priority_queue<Point>q;
int main(){
scanf("%d%d",&n,&m);
while(!q.empty())q.pop();
for(int i=1;i<=n;++i){
scanf("%lld",&sum[i]);
h[i]=0;
q.push(Point(i));
}
nn=n;
if(m!=2){
for(int l=1;;++l){
if((m-1)*l+1>=n){
for(int i=n+1;i<=(m-1)*l+1;++i){
sum[++nn]=0;h[nn]=0;
q.push(Point(i));
}
break;
}
}
}
while(q.size()!=1){
++nn;
for(int i=1;i<=m;++i){
int t=q.top().x;q.pop();
h[nn]=max(h[nn],h[t]+1);
sum[nn]+=sum[t];
}
ansh=max(ansh,h[nn]);
anssum=anssum+sum[nn];
q.push(Point(nn));
}
printf("%lld\n",anssum);
printf("%lld\n",ansh);
return 0;
}