zoukankan      html  css  js  c++  java
  • $HDU 2020$ 多校第六场

    (6832 A Very Easy Graph Problem)

    题意

    给定一张 (n) 个顶点,(m) 条边的无向图,输入的第 (i) 条边的权值为 (2^i)

    对于每一个顶点,标记为 (0)(1)

    请计算

    [sum_{i = 1}^{n}sum_{j = 1}^ndis(i, j) imes left[a_{i} = 1wedge a_{j} = 0 ight] ]

    其中 (dis(i, j)) 表示 (i)(j) 的最短路

    (left[a_{i} = 1wedge a_{j} = 0 ight])(Iverson bracket),即条件成立取值为 (1),不成立取值为 (0)

    (1leq nleq 10^5, 1leq mleq 2 imes 10^5),对答案取模 (10^9 + 7)

    题解

    题意等价于,计算所有 (1) 点到所有 (0) 点的最短路之和

    注意到边权的特殊性,即 (2^i > 2^1 + 2^2 + ... + 2^{i - 1})

    设当前输入边 (i),端点为 (u, v)

    • (u, v) 已联通,那么必然有 (dis(u, v) < 2^i)
    • (u, v) 未联通,那么必然有 (dis(u, v) = 2^i)

    所以考虑,对所有边按输入顺序构造 (MST),模拟 (Kruskal) 算法,得到一颗生成树

    由前面的证明知道,这颗生成树的特殊之处在于

    • 是一颗最小生成树
    • 树上任意两点的距离一定是最短路径

    下面在新的树上作树形 (dp),记录节点所在子树的 (0) 点和 (1) 点的数量,枚举树上每一条边计算贡献即可

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define dbg(a, l, r) for(int i = l; i <= r; ++i) printf("%lld%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 2e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    
    int T, n, m, zero, one, a[N], pre[N], rk[N], dp[N][2];
    vector<pii> g[N];
    pii E[N];
    void ini(int n) {for(int i = 1; i <= n; ++i) pre[i] = i, rk[i] = 1;}
    int findPre(int x) {return pre[x] == x ? x : pre[x] = findPre(pre[x]);}
    void uni(int x, int y)
    {
        int fx = findPre(x), fy = findPre(y);
        if(fx == fy) return;
        if(rk[fx] < rk[fy]) pre[fx] = fy, rk[fy] += rk[fx];
        else pre[fy] = fx, rk[fx] += rk[fy];
    }
    bool commonpre(int x, int y) {int fx = findPre(x), fy = findPre(y); return fx == fy;}
    
    void debug()
    {
        for(int i = 1; i <= n; ++i) {
            cout << i << ":" << endl;
            for(auto it: g[i]) cout << it.fi << ' ';
            cout << endl;
        }
        for(int i = 1; i <= n; ++i) {
            cout << i << ":" << endl;
            cout << "0's num: " << dp[i][0] << endl;
            cout << "1's num: " << dp[i][1] << endl;
        }
    }
    void dfs(int u, int v, LL &ans)
    {
        dp[u][a[u]]++;
        for(auto i: g[u]) {
            if(i.fi != v) {
                dfs(i.fi, u, ans);
                dp[u][0] += dp[i.fi][0];
                dp[u][1] += dp[i.fi][1];
            }
        }
        for(auto i: g[u]) {
            if(i.fi != v) {
                LL res1 = dp[i.fi][0] * (one - dp[i.fi][1]) % MOD * i.se % MOD;
                LL res2 = dp[i.fi][1] * (zero - dp[i.fi][0]) % MOD * i.se % MOD;
                ans = (ans + res1 + res2) % MOD;
            }
        }
    }
    int main()
    {
        scanf("%d", &T);
        while(T--) {
            scanf("%d %d", &n, &m);
            memset(dp, 0, sizeof(dp));
            zero = one = 0;
            for(int i = 0; i <= n; ++i) g[i].clear();
            ini(n);
            for(int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
                if(a[i] == 0) zero++;
                else one++;
            }
            for(int i = 1; i <= m; ++i) {
                int u, v;
                scanf("%d %d", &u, &v);
                E[i] = pii(u, v);
            }
            int cnt = 0;
            LL tp = 1, ans = 0;
            for(int i = 1; i <= m; ++i) {
                int x = E[i].fi, y = E[i].se;
                tp *= 2, tp %= MOD;
                if(!commonpre(x, y)) {
                    uni(x, y);
                    g[x].pb(pii(y, tp));
                    g[y].pb(pii(x, tp));
                    if(cnt == n - 1) break;
                }
            }
            dfs(1, -1, ans);
            //debug();
            printf("%lld
    ", ans);
        }
        return 0;
    }
    /*
    3
    3 2
    0 1 0
    3 1
    3 2
    3 2
    1 1 0
    3 1
    3 2
    4 4
    1 0 1 0
    1 2
    2 3
    3 4
    1 4
    */
    
  • 相关阅读:
    97. Interleaving String
    96. Unique Binary Search Trees
    95. Unique Binary Search Trees II
    94. Binary Tree Inorder Traversal
    odoo many2many字段 指定打开的form视图
    docker sentry 配置文件位置
    postgres 计算时差
    postgres 字符操作补位,字符切割
    postgres判断字符串是否为时间,数字
    odoo fields_view_get
  • 原文地址:https://www.cnblogs.com/ChenyangXu/p/13449595.html
Copyright © 2011-2022 走看看