P2986 [USACO10MAR] Great Cow Gathering G

原题链接

题解

很简单想到暴力,但是 O(n2) 显然不行
所以要减少计算量,如何利用已经计算过的值而不是重新算一遍呢?
这道题最好看成有中心点的网状图,而不是树状图

随便取一个点 A 作为根节点,很容易计算其答案,如何计算以其他点为根节点的答案呢?
对于以根节点的邻边节点 B 为根节点的图,其答案相当于原本 A 点的答案加上 A 点的所有奶牛迁移到 B 点的消耗,又因为以 B 节点为根节点的子树(相对于 A 来说)重复走了两段
所以减去这个重复的两端就是 B 点的答案
如果这个过程以 有中心点的网状图 来看很容易理解

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct edge
{
    ll to,val;
};
vector<edge> G[100005];
ll c[100005]={0};
ll sum1[100005]={0},ans1[100005]={0};
ll ans[100005]={0};
ll total=0;
void ss(ll now,ll fa)
{
    sum1[now]=c[now];
    for(ll i=0;i<G[now].size();i++)
    {
        ll next=G[now][i].to,len=G[now][i].val;
        if(next==fa)continue;

        ss(next,now);
        ans1[now]+=sum1[next]*len+ans1[next];
        sum1[now]+=sum1[next];
    }
}

void turn(ll now,ll fa)
{
    for(ll i=0;i<G[now].size();i++)
    {
        ll next=G[now][i].to,len=G[now][i].val;
        if(next==fa)continue;

        ans[next]=(total-2*sum1[next])*len+ans[now];
        turn(next,now);
    }
}

int main()
{
    ll n;
    cin>>n;
    for(ll i=1;i<=n;i++)
    {
        cin>>c[i];
        total+=c[i];
    }

    for(ll i=1;i<=n-1;i++)
    {
        ll x,y,l;
        cin>>x>>y>>l;
        G[x].push_back({y,l});
        G[y].push_back({x,l});
    }

    ss(1,0);
    ans[1]=ans1[1];
    turn(1,0);

    ll sum=2e18;
    for(ll i=1;i<=n;i++)
    {
        //cout<<ans[i]<<endl;
        sum=min(sum,ans[i]);
    }
    cout<<sum<<endl;
    return 0;
}

posted @   纯粹的  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示