lcrtest的博客

一个SC蒟蒻的blog

bzoj 4632: 树的编码

首先根节点的长度为0
我们观察,如果当前子树根节点长度为x,那么他的子树内节点长度不小于x
如果只有一个儿子,那么这个儿子编码和父亲编码是一样的
如果有两个儿子,那么这两个儿子分别+1+0
显然这是一个贪心问题,考虑对于x节点如何贪心
我们把它所有的儿子扒出来,然后按照size排序,对于这些size构建哈夫曼树,这样某个节点在哈夫曼树上的deep1就是这个节点与父亲的长度差
那么对于每个节点都这个做一遍就好了
时间复杂度O(Nlog2N)

#include<bits/stdc++.h>
#define sp new int[cnt<<1]
const int N=100010;
using namespace std;
int to[N],nxt[N],sz,fir[N],size[N],n,S,tot;
long long ans;
void add(int x,int y){
    nxt[++sz]=fir[x],fir[x]=sz,to[sz]=y;
}
#define add2(x,y) tnxt[++tsz]=tfir[x],tfir[x]=tsz,tto[tsz]=y;
void dfs1(int x){
    size[x]=1;
    for(int u=fir[x];u;u=nxt[u]){
        dfs1(to[u]);
        size[x]+=size[to[u]];
    }
}
struct node{
    int x,v;
    bool operator<(const node&a)const{
        return v>a.v;
    }
};
void dfs(int x,int*dfn,int*l,int dep,int*tfir,int*tnxt,int*tto){
    if(x<=S){
        dfn[++tot]=x;l[tot]=dep;return;
    }
    for(int u=tfir[x];u;u=tnxt[u]){
        dfs(tto[u],dfn,l,dep+1,tfir,tnxt,tto);
    }
}
void dfs2(int x,int len){
    ans+=len;
    priority_queue<node>q;
    int cnt=0;
    for(int u=fir[x];u;u=nxt[u]){
        cnt++;q.push((node){cnt,size[to[u]]});
    }
    if(!cnt)return;S=cnt;
    int *tfir=sp,tsz=0,*tnxt=sp,*tto=sp,*who=sp,*dfn=sp,*l=sp;
    for(int i=0;i<cnt<<1;i++)tfir[i]=tnxt[i]=tto[i]=who[i]=dfn[i]=l[i]=0;
    cnt=0;
    for(int u=fir[x];u;u=nxt[u]){
        cnt++;who[cnt]=to[u];
    }
    while(q.size()>1){
        node a=q.top();q.pop();
        node b=q.top();q.pop();
        ++cnt;add2(cnt,a.x);add2(cnt,b.x);
        q.push((node){cnt,a.v+b.v});
    }
    tot=0;
    dfs(cnt,dfn,l,0,tfir,tnxt,tto);
    for(int i=1;i<=(cnt+1)>>1;i++)dfs2(who[dfn[i]],len+l[i]);
}
int main(){
    scanf("%d\n",&n);
    for(int i=2;i<=n;i++){
        int x;scanf("%d",&x);add(x,i);
    }
    dfs1(1);
    dfs2(1,0);
    cout<<ans<<endl;
}
阅读更多
版权声明:233333333333333333333333333333333333333333 https://blog.csdn.net/lcrtest/article/details/51862131
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭