快乐树论

Description

 曾经有一位伟大的皇帝,他拥有n座城池并用n-1条无向道路相连,每条道路均有一个确定的长度和两个端点,保证城池与城池之间互达。有一天,皇帝决定将其中一条路拆掉,并重新将这条道路以同样的长度搭在两座城池之间,皇帝可能将这条路拆了又重新建在原处。现在皇帝想问问你,在只拆掉一条道路并重新建造一条同样长的在两座城池之间后,任意两个城池之前的距离和最小为多少呢?

 

Input

 第一行输入一个n代表皇帝有n座城池,接下来n-1行输入a,b,c代表城池a,b之间有一条长为c的道路。 (2 ≤ n ≤ 5000, 1 ≤ ai, bi ≤ n, ai ≠ bi, 1 ≤ wi ≤ 106)

 

Output

 输出一行任意两城池之间的最小距离和。

 

Sample Input

输入样例1: 3 1 2 2 1 3 4 输入样例2: 6 1 2 1 2 3 1 3 4 1 4 5 1 5 6 1 输入样例3: 6 1 3 1 2 3 1

Sample Output

输出样例1: 12 输出样例2: 29 输出样例3: 825

HINT

 

 实际输入输出中并没有“输入样例1”, “输出样例1:” 之类 这种东西,这里只是为了多给几组数据,让大家更容易的理解用的

题解:

具体证明参考:https://blog.csdn.net/zhoufenqin/article/details/9821617

#include<bits/stdc++.h>

#define fi first
#define se second
#define pb push_back

using namespace std;

typedef long long ll;
typedef pair<ll,ll> Pll;

const ll LLMAX=2e18;
const int MAXN=1e6+10;

struct node{
    int u,v;
    ll w;
}in[MAXN];

ll dp[MAXN][3];
vector<Pll>G[MAXN];

void dfs(int u,int pre){
    dp[u][0]=dp[u][1]=dp[u][2]=0;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].fi,w=G[u][i].se;
        if(v==pre)   continue;
        dfs(v,u);
        dp[u][2]+=dp[v][2]+dp[v][1]*dp[u][0]+dp[v][0]*dp[u][1]+dp[u][0]*dp[v][0]*w;
        dp[u][1]+=dp[v][1]+dp[v][0]*w;
        dp[u][0]+=dp[v][0];            
    }
    dp[u][0]++;
    dp[u][2]+=dp[u][1];
}

void solve(int u,int pre,ll &ans){
    ans=min(ans,dp[u][1]);
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].fi,w=G[u][i].se;
        if(v==pre)  continue;
        dp[v][1]=dp[v][1]+(dp[u][1]-dp[v][1]-w*dp[v][0])+(dp[u][0]-dp[v][0])*w;
        dp[v][0]=dp[u][0];
        solve(v,u,ans);
    }
}

int main(void)
{
    ios::sync_with_stdio(false);    cin.tie(0);
    ll n,ans=LLMAX;  cin>>n; 
    for(int i=1;i<n;i++){
        ll x,y,v;  cin>>x>>y>>v;    
        in[i].u=x,in[i].v=y,in[i].w=v;
        G[x].pb(Pll(y,v)),G[y].pb(Pll(x,v));
    }
    for(int i=1;i<n;i++){
        ll ans1=LLMAX,ans2=LLMAX,u=in[i].u,v=in[i].v,w=in[i].w;
        dfs(u,v);   solve(u,v,ans1);
        ll len1=(n-dp[u][0])*ans1+dp[u][2];
        dfs(v,u);   solve(v,u,ans2);
        ll len2=(n-dp[v][0])*ans2+dp[v][2];
        ans=min(ans,len1+len2+dp[u][0]*dp[v][0]*w);
    }
    cout<<ans<<endl;
    return 0;
}

 

全部评论

相关推荐

小红书 后端开发 总包n+8w+期权
点赞 评论 收藏
分享
邮小鼠:粤嵌的项目水的要死 来我们学校带过课程实习 项目名字是车机终端 实际上就是写了了个gui 还是老师把代码发给你你改改的那种
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务