1. 程式人生 > 實用技巧 >Luogu P2168 [NOI2015]荷馬史詩

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;
		}
	}
}