bzoj4198 noi2015 荷马史诗

k叉哈夫曼树,平衡整颗树即可

然后开个双队列由小到大做

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,x) for(int i=last[x];i!=0;i=e[i].next)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s-getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 100005
LL a[N],w[N];
int n,m;
struct edge
{
	LL num,dep;
}sta1[N],sta2[N];
LL h1=1,h2=1,t1,t2=0;

edge get()
{
	if(h2>t2)return sta1[h1++];
	if(h1>t1)return sta2[h2++];
	if(sta1[h1].num==sta2[h2].num)
	{
		if(sta1[h1].dep<sta2[h2].dep)return sta1[h1++];
		else return sta2[h2++];
	}
	if(sta1[h1].num<sta2[h2].num)return sta1[h1++];
	else return sta2[h2++];
}

void add(LL x,int de)
{
	sta2[++t2].num=x;
	sta2[t2].dep=de;
}

void check()
{
	cout<<"New:\n";
	cout<<h1<<' '<<t1<<' '<<h2<<' '<<t2<<endl;
	cout<<"stack1.num:";
	fo(i,h1,t1)cout<<sta1[i].num<<' ';cout<<endl;
	cout<<"stack1.dep:";
	fo(i,h1,t1)cout<<sta1[i].dep<<' ';cout<<endl;
	cout<<"stack2.num:";
	fo(i,h2,t2)cout<<sta2[i].num<<' ';cout<<endl;
	cout<<"stack2.dep:";
	fo(i,h2,t2)cout<<sta2[i].dep<<' ';cout<<endl;
}

int main()
{
	memset(w,0,sizeof(w));
	n=read();m=read();
	fo(i,1,n)w[i]=read();
	while((n-1)%(m-1)!=0)n++;
	sort(w+1,w+n+1);
	fo(i,1,n)
	{
		sta1[i].num=w[i];
		sta1[i].dep=0;
	}
	int cnt=n,dep=1;t1=n;
	LL ans=0;
	while(cnt!=1)
	{
		LL ret=0,len=0;
		fo(i,1,m)
		{
			edge t=get();
			ret+=t.num,cnt--;
			len=max(len,t.dep);
		}
		ans+=ret;
		add(ret,len+1);cnt++;
//		check();
	}
	cout<<ans<<endl<<sta2[h2].dep<<endl;
	return 0;
}


你可能感兴趣的:(k叉哈夫曼树)