题目大意:k叉哈夫曼树,且要求最大深度最小
对于第一条,先将多余的部分也就是n%(k-1)个预先合并,注意如果n%(k-1)==1就不要合并了,n%(k-1)==0要合并k-1个。
最大深度最小,直接贪心即可。
std::priority_queue慢得吓人
#include<cstdio>
#include<queue>
#define gm 100001
using namespace std;
typedef unsigned long long ll;
inline ll max(const ll &a,const ll &b)
{
return a<b?b:a;
}
struct node
{
node* f;
ll w;
ll d;
node():f(0),w(0),d(0){}
inline void son(node* const &x)
{
x->f=this;
w+=x->w;
d=max(d,x->d+1);
}
}word[gm],*now;
typedef node* elec;
#define cmp(a,b) (a->w<b->w || a->w==b->w&&a->d<b->d)
struct heap
{
typedef unsigned int u;
elec h[gm];
u n;
heap(u n):n(n)
{
for(int i=1;i<=n;i++)
h[i]=word+i;
for(int i=n>>1;i>=1;i--)
down(i);
}
inline void down(u x)
{
static u j;
static elec v;
v=h[x];
while((x<<1)<=n)
{
j=x<<1;
if(j+1<=n&&cmp(h[j+1],h[j]))
j++;
if(cmp(h[j],v))
{
h[x]=h[j];
x=j;
}
else break;
}
h[x]=v;
}
inline elec top()
{
return h[1];
}
inline void pop()
{
h[1]=h[n--];
down(1);
}
inline void push(const elec &v)
{
static u x;
x=++n;
while(x>1)
{
if(cmp(v,h[x>>1]))
{
h[x]=h[x>>1];
x>>=1;
}
else break;
}
h[x]=v;
}
};
int n,k;
ll getdpt(elec x)
{
ll res=0;
while(x->f)
++res,x=x->f;
return res;
}
int main()
{
//freopen("epic.in","r",stdin);
//freopen("epic.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%llu",&word[i].w);
heap& h=*(new heap(n));
int rem=n%(k-1);
if(!rem) rem=k-1;
if(rem!=1)
{
now=new node;
for(int i=1;i<=rem;i++)
{
now->son(h.top());
h.pop();
}
h.push(now);
}
rem=n-rem+1;
for(;rem!=1;rem-=k-1)
{
now=new node;
for(int j=1;j<=k;j++)
{
now->son(h.top());
h.pop();
}
h.push(now);
}
ll minlen=0;
ll maxlen=0;
ll kre;
for(int i=1;i<=n;i++)
{
kre=getdpt(word+i);
minlen+=kre*word[i].w;
maxlen=max(maxlen,kre);
}
printf("%llu\n%llu\n",minlen,maxlen);
return 0;
}

本文介绍了一种实现K叉哈夫曼树的方法,并通过贪心算法来构造树,确保最大深度最小。代码中使用自定义堆结构来优化节点合并过程,避免使用标准库中的priority_queue。
598

被折叠的 条评论
为什么被折叠?



