Abandoned country HDU - 5723

题目链接
题意:给你一棵树,让你求每个点之间的距离的最短之和
题解:看到最短之和,想到最小生成树,且每条边权不同,最小生成树唯一,就转换问题为,求一棵树上每个点到所有点的距离之和,这就是树形dp,先对一个点跑dfs,求出该点到所有点的距离之和,统计每个点的子树个数,并假设该点为根,再跑一次dfs统计\(dp\)
\(dp_i\)为第i个节点到每个点的路径之和,假设\(j\)是他的子节点,容易知,有\(siz_j\)个节点到\(j\)的距离比到\(i\)少权值\(w\),有\(n-siz_j\)个节点到\(j\)的距离比到\(i\)多权值\(w\)
那就可以得到关系式:\(dp_j = dp_i - w*siz_j + w*(n-siz_j) = dp_i - w*(n-2*siz_j)\)
因为有1e6条边,用prim要用链式前向星存图即可

#include<bits/stdc++.h>
using namespace std;
#define ms(x,y) memset(x, y, sizeof(x))
#define lowbit(x) ((x)&(-x))
typedef long long LL;
typedef pair<int,int> pii;


const int maxn = 1e5+7;
const int maxm = 1e6+7;
int head1[maxm<<1], head2[maxn<<1], edgecnt1, edgecnt2, siz[maxn], n, m;
bool vis[maxn];
LL dp[maxn];
struct Node {
    int u, v, w, nex;
} edges1[maxm<<1], edges2[maxn<<1];

struct edge {
    int u, v, w;
    edge(int _u, int _v, int _w):u(_u), v(_v), w(_w){}
    bool operator < (const edge a) const {
        return a.w < w;
    }
};

void addedge1(int u, int v, int w) {
    edges1[edgecnt1] = Node{u, v, w, head1[u]};
    head1[u] = edgecnt1++;
    edges1[edgecnt1] = Node{v, u, w, head1[v]};
    head1[v] = edgecnt1++;
}

void addedge2(int u, int v, int w) {
    edges2[edgecnt2] = Node{u, v, w, head2[u]};
    head2[u] = edgecnt2++;
    edges2[edgecnt2] = Node{v, u, w, head2[v]};
    head2[v] = edgecnt2++;
}

void init() {
    ms(head1, -1), ms(head2, -1), ms(vis, false);
    edgecnt1 = edgecnt2 = 0;
    dp[1] = 0;
}

LL prim() {
    LL minsum = 0;
    priority_queue<edge> q;
    vis[1] = true;
    for(int i = head1[1]; i != -1; i = edges1[i].nex) {
        int v = edges1[i].v, w = edges1[i].w;
        q.push(edge(1, v, w));
    }
    while(!q.empty()) {
        auto now = q.top();
        q.pop();
        if(vis[now.v]) continue;
        vis[now.v] = true;
        minsum += now.w;
        int u = now.v;
        addedge2(now.u, u, now.w);
        for(int i = head1[u]; i != -1; i = edges1[i].nex) {
            int v = edges1[i].v, w = edges1[i].w;
            if(vis[v]) continue;
            q.push(edge{u, v, w});
        }
    }
    return minsum;
}

void dfs1(int u, int fa, LL val, LL &ans) {
    siz[u] = 1;
    ans += val;
    for(int i = head2[u]; i != -1; i = edges2[i].nex) {
        int v = edges2[i].v;
        if(v == fa) continue;
        dfs1(v, u, val+edges2[i].w, ans);
        siz[u] += siz[v];
    }
}

void dfs2(int u, int fa, LL &ans) {
    for(int i = head2[u]; i != -1; i = edges2[i].nex) {
        int v = edges2[i].v, w = edges2[i].w;
        if(v == fa) continue;
        dp[v] = dp[u] + 1LL*w*(n-2*siz[v]);
        ans += dp[v];
        dfs2(v, u, ans);
    }
}

void run_case() {
    init();
    cin >> n >> m;
    for(int i = 0; i < m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        addedge1(u, v, w);
    }
    LL ans1 = prim(); 
    dfs1(1, 0, 0, dp[1]);
    LL ans2 = dp[1];
    dfs2(1, 0, ans2);
    cout << ans1 << " " << (double)ans2/n/(n-1) << "\n";
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cout.flags(ios::fixed);cout.precision(2);
    int t; cin >> t;
    while(t--)
    run_case();
    cout.flush();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/GRedComeT/p/12379894.html