Luogu P2168 [NOI2015]荷马史诗

https://www.luogu.com.cn/problem/P2168

题面

给定一棵含\(n\)个叶子节点的\(k\)叉树,其中第\(i\)的叶子有点权\(a_i\),要求最小化\(\sum w_i\times l_i\)
其中\(l_i\)表示到根节点的距离
并求出在权值和最小的情况下树的最小深度

分析

huffman树
先将\(k\)叉树用权值为0的点补满,然后每次选出权值最小的\(k\)个点合并
可以用堆实现,但更能用队列实现
先将叶子节点排序,再对合并的点单独开一个队列
因为随着合并数的增加,点权大小是严格递增的

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=1e5+5;
int n,k,l,r; ll a[N],ans;
struct A{ll x; int y; }q[N];

int main() {
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) {
		scanf("%lld",&a[i]);
	}
	while((n-1)%(k-1)) n++;
	sort(a+1,a+n+1);
	int L=1; l=1,r=0;
	for(int i=n;i;i-=k-1) {
		A t=(A){0,0};
		for(int j=1;j<=k;j++) {
			if(l>r||L<=n&&a[L]<=q[l].x) {
				t.x+=a[L],L++;
			} else {
				t.x+=q[l].x,t.y=max(t.y,q[l].y),l++;
			}
		}
		ans+=t.x,t.y++;
		q[++r]=t;
		if(i==k) {
			printf("%lld\n%d\n",ans,t.y);
			return 0;
		}
	}
}
posted @ 2020-11-27 15:01  wwwsfff  阅读(66)  评论(0)    收藏  举报