Codeforces 437D The Child and Zoo

先是我们看到题目中让我们处理点权,但是我们发现并不好处理

所以就先化点为边

把每一条边的边权视作边所连接的两个点的\(min\)

然后我们看到这个题有路径的问题,就先还是要较大的

可以比较显然地想到最大生成树

\(Kruskal\)中改一下排序方式就行了

然后我们看到不是生成树上的边都我们在考虑走的时候都不会考虑

考虑每一个树边的贡献

连接两个联通块的时候

这一条边会产生\(val[edge]* size[x]* size[y]\)的贡献

然后就是并查集完事

Code

const int N = 1e5 + 10;
const int M = 1e6 + 10;
struct node {
    int from, to, dis;
    bool operator<(const node &x) { return dis > x.dis; }
} e[M];
int n, m, val[N], sz[N], cnt, tot, fa[N];
inline void add(int u, int v, int w) {
    e[++cnt].dis = w;
    e[cnt].from = u;
    e[cnt].to = v;
    return;
}
inline int find(int x) { return fa[x] == x ? fa[x] : fa[x] = find(fa[x]); }
int u, v, w, ans;
signed main() {
    n = read();
    m = read();
    for (int i = 1; i <= n; ++i) fa[i] = i, sz[i] = 1;
    for (int i = 1; i <= n; ++i) val[i] = read();
    for (int i = 1; i <= m; ++i) u = read(), v = read(), add(u, v, min(val[u], val[v]));
    sort(e + 1, e + m + 1);
    for (int i = 1; i <= m; ++i) {
        int x = find(e[i].from), y = find(e[i].to);
        if (x == y)
            continue;
        fa[x] = y;
        tot++;
        ans += sz[x] * sz[y] * e[i].dis;
        sz[y] += sz[x];
        if (tot == n - 1)
            break;
    }
    ans *= 2;
    double x = n * (n - 1);
    printf("%.8lf", (double)ans / x);
    return 0;
}
posted @ 2020-02-03 17:31  yspm  阅读(131)  评论(0编辑  收藏  举报