zoukankan      html  css  js  c++  java
  • Abandoned country HDU

    题目链接
    题意:给你一棵树,让你求每个点之间的距离的最短之和
    题解:看到最短之和,想到最小生成树,且每条边权不同,最小生成树唯一,就转换问题为,求一棵树上每个点到所有点的距离之和,这就是树形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) << "
    ";
    }
    
    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;
    }
    
  • 相关阅读:
    原生JavaScript事件详解
    如何真正重写window对象的方法
    JSLint JavaScript代码质量审查工具汉化中文版隆重发布
    {{偷偷告诉你}}本博客已适配移动端浏览
    谷歌(Chrome)浏览器调试JavaScript小技巧
    小米Web前端JavaScript面试题
    根据配置文件加载js依赖模块(JavaScript面试题)
    中移杭州研发中心
    MyBatis与Hibernate区别
    hashmap源码解析,JDK1.8和1.7的区别
  • 原文地址:https://www.cnblogs.com/GRedComeT/p/12379894.html
Copyright © 2011-2022 走看看