hdoj6446(树形DP)

Posted frankchen831x

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdoj6446(树形DP)相关的知识,希望对你有一定的参考价值。

题目链接:https://vjudge.net/problem/HDU-6446

题意:简化题意后就是求距离和的2*(n-1)!倍。

思路:

  简单的树形dp,通过求每条边的贡献计算距离和,边(u,v)的贡献为sz[v]*(n-sz[v])。

#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=1e5+5;
const int MOD=1e9+7;
int n,cnt,head[maxn],sz[maxn];
LL ans;

struct node
    int v,nex;
    LL w;
edge[maxn<<1];

void adde(int u,int v,LL w)
    edge[++cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nex=head[u];
    head[u]=cnt;


void dfs(int u,int fa)
    sz[u]=1;
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(v==fa) continue;
        dfs(v,u);
        sz[u]+=sz[v];
        ans=(ans+edge[i].w*sz[v]%MOD*(n-sz[v])%MOD)%MOD;
    


int main()
    while(~scanf("%d",&n))
        ans=0;
        cnt=0;
        for(int i=1;i<=n;++i)
            head[i]=0;
        for(int i=1;i<n;++i)
            int u,v;LL w;
            scanf("%d%d%lld",&u,&v,&w);
            adde(u,v,w);
            adde(v,u,w);
        
        dfs(1,0);
        for(int i=1;i<n;++i)
            ans=ans*i%MOD;
        ans=ans*2%MOD;
        printf("%lld\n",ans);
    
    return 0;

 

  另外因为前几天学点分治,看到这题想到可以用点分治求距离和。具体做法是,通过求得重心u后求所有点到重心的距离dis[i],然后采用点分治的第二种写法,遍历u的所有子结点v,用sum表示前面计算过的距离总和,num表示前面的结点数,那么对当前遍历的dis[i],其贡献为num*dis[i]+sum。但要注意不要漏了以重心为端点的边,所以将num初始化1,而不是0。

  点分治代码:

技术图片
#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=1e5+5;
const int MOD=1e9+7;
const int inf=0x3f3f3f3f;
int n,cnt,head[maxn],sz[maxn],mson[maxn],Min,size,root;
int vis[maxn],t,num;
LL dis[maxn],tmp,sum,ans;

struct node
    int v,nex;
    LL w;
edge[maxn<<1];

void adde(int u,int v,LL w)
    edge[++cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nex=head[u];
    head[u]=cnt;


void getroot(int u,int fa)
    sz[u]=1,mson[u]=0;
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        getroot(v,u);
        sz[u]+=sz[v];
        mson[u]=max(mson[u],sz[v]);
    
    mson[u]=max(mson[u],size-sz[u]);
    if(mson[u]<Min) Min=mson[u],root=u;


void getdis(int u,int fa,LL len)
    dis[++t]=len;
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        getdis(v,u,(len+edge[i].w)%MOD);
    


void solve(int u)
    sum=0;
    num=1;
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(vis[v]) continue;
        t=0;
        tmp=0;
        getdis(v,u,edge[i].w);
        for(int i=1;i<=t;++i)
            ans=(ans+num*dis[i]%MOD+sum)%MOD;
            tmp=(tmp+dis[i])%MOD;
        
        sum=(sum+tmp)%MOD;
        num+=t;
    


void fenzhi(int u,int ssize)
    vis[u]=1;
    solve(u);
    for(int i=head[u];i;i=edge[i].nex)
        int v=edge[i].v;
        if(vis[v]) continue;
        Min=inf,root=0;
        size=sz[v]<sz[u]?sz[v]:(ssize-sz[u]);
        getroot(v,0);
        fenzhi(root,size);
    


int main()
    while(~scanf("%d",&n))
        cnt=0;
        ans=0;
        for(int i=1;i<=n;++i)
            head[i]=vis[i]=0;
        for(int i=1;i<n;++i)
            int u,v;LL w;
            scanf("%d%d%lld",&u,&v,&w);
            adde(u,v,w);
            adde(v,u,w);
        
        Min=inf,root=0,size=n;
        getroot(1,0);
        fenzhi(root,n);
        for(int i=1;i<n;++i)
            ans=ans*i%MOD;
        ans=ans*2%MOD;
        printf("%lld\n",ans);
    
    return 0;
View Code

 

以上是关于hdoj6446(树形DP)的主要内容,如果未能解决你的问题,请参考以下文章

HDOJ 4705 Y 树形DP

[HDOJ2196]Computer (树直径 树形DP)

HDOJ 题目1520 Anniversary party(树形dp)

HDOJ6686Rikka with Travels(树形DP)

hdoj4276(树形dp+分组背包)

HDOJ2196Computer(树的直径,树形DP)