P2986 [USACO10MAR]Great Cow Gathering G(换根dp)

题目传送门

本题是这题的延伸。

题意: 有一颗树,你可以选定一个根节点,这个根节点的代价是 ∑ c [ i ] ∗ d i s [ i ] \sum c[i]*dis[i] c[i]dis[i] c [ i ] c[i] c[i]表示点i的点权值, d i s [ i ] dis[i] dis[i]表示点i到根节点的距离。

思路: 先处理出以1为根节点的时候的代价,然后再遍历这棵树,根据方程转移即可。

  • f [ t o ] = f [ x ] − s i z [ i ] ∗ d i s ( x , t o ) + ( t o t c [ i ] − s i z [ i ] ) ∗ d i s ( x , t o ) f[to]=f[x]-siz[i]*dis(x,to)+(tot_{c[i]}-siz[i])*dis(x,to) f[to]=f[x]siz[i]dis(x,to)+(totc[i]siz[i])dis(x,to)

s i z [ i ] siz[i] siz[i]表示子树i中c[i]的和。

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define pii pair<int,int>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read()
{
    
    
    int x=0,f=1;
    char ch=gc();
    while(ch<'0'||ch>'9')
    {
    
    
        if(ch=='-')
            f=-1;
        ch=gc();
    }
    while(ch>='0'&&ch<='9')
    {
    
    
        x=x*10+ch-'0';
        ch=gc();
    }
    return x*f;
}
using namespace std;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-7;

vector<pii>e[N];
int siz[N],f[N],n,c[N],m=0;
void dfs1(int fa,int x,int dis)
{
    
    
    siz[x] = c[x];
    for(auto i:e[x])
    {
    
    
        if(i.first==fa)
            continue;
        dfs1(x,i.first,dis+i.second);
        siz[x]+=siz[i.first];
    }
    f[1] = f[1] + c[x]*dis;
}
void dfs2(int fa,int x)
{
    
    
    for(auto i:e[x])
    {
    
    
        if(i.first==fa)
            continue;
        int to = i.first;
        f[to] = f[x]-siz[to]*i.second+(m-siz[to])*i.second;
        dfs2(x,to);
    }
}
void solve()
{
    
    
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>c[i],m+=c[i];
    for(int i=1;i<n;i++)
    {
    
    
        int u,v,w;
        cin>>u>>v>>w;
        e[u].pb(mp(v,w));
        e[v].pb(mp(u,w));
    }
    dfs1(1,1,0);
    dfs2(1,1);
    cout<<*min_element(f+1,f+n+1)<<endl;
}

signed main()
{
    
    
    solve();

    return 0;
}

猜你喜欢

转载自blog.csdn.net/Joker_He/article/details/113056481