Codeforces 437D The Child and Zoo

这个题还是很好的

有几个套路

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

所以就先化点为边 (套路1)

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

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

可以比较显然地想到最大生成树 (套路2)

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

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

考虑每一个树边的贡献

连接两个联通块的时候

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

然后就是并查集完事

CODE:

#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm {
inline int read() {
    int res = 0, f = 1;
    char k;
    while (!isdigit(k = getchar())) {
        if (k == '-')
            f = -1;
    }
    while (isdigit(k)) {
        res = res * 10 + k - '0';
        k = getchar();
    }
    return res * f;
}
inline int max(int x, int y) { return x > y ? x : y; }
inline int min(int x, int y) { return x < y ? x : y; }
inline void swap(int &x, int &y) {
    int z = x;
    x = y;
    y = z;
    return;
}
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;
}
}  // namespace yspm
signed main() {
    yspm::main();
    return 0;
}

原文地址:https://www.cnblogs.com/yspm/p/12256494.html

时间: 2024-12-08 05:06:50

Codeforces 437D The Child and Zoo的相关文章

Codeforces 437D The Child and Zoo(贪心+并查集)

题目链接:Codeforces 437D The Child and Zoo 题目大意:小孩子去参观动物园,动物园分很多个区,每个区有若干种动物,拥有的动物种数作为该区的权值.然后有m条路,每条路的权值为该条路连接的两个区中权值较小的一个.如果两个区没有直接连接,那么f值即为从一个区走到另一个区中所经过的路中权值最小的值做为权值.问,平均两个区之间移动的权值为多少. 解题思路:并查集+贪心.将所有的边按照权值排序,从最大的开始连接,每次连接时计算的次数为连接两块的节点数的积(乘法原理). #in

Codeforces Round #250 (Div. 1) B. The Child and Zoo(排序+并查集)(常规好题)

B. The Child and Zoo time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Of course our child likes walking in a zoo. The zoo has n areas, that are numbered from 1 to n. The i-th area contains 

Codeforces 437 D. The Child and Zoo 并查集

题目链接:D. The Child and Zoo 题意: 题意比较难懂,是指给出n个点并给出这些点的权值,再给出m条边.每条边的权值为该条路连接的两个区中权值较小的一个.如果两个区没有直接连接,那么f值即为从一个区走到另一个区中所经过的路中权值最小的值做为权值.如果有多条路的话,要取最大的值作为路径的长度.问,平均两个区之间移动的权值为多少. 题解: 每条边的长度已经知道了,因为路径的权值取这条路中最小的且多条路的话则取较大的,那么我们其实可以从比较大的边开始取(先把边排序),用并查集开始合并

Codeforces 437D 贪心+并查集

这个题目让我想起了上次在湘潭赛的那道跪死了的题.也是最值问题,这个也是,有n个动物园 每个都有权值 然后被m条路径相连接,保证图是连通的,然后求所有的p[i][j]之和.i,j为任意两个zoo,pij就为i到j路上遇到的包括i j在内的最小权值的zoo 然后我就焦头烂额了一下,这个明显就是看某个最小值为最后的结果发挥了多少次作用,但这个是图,要知道某个节点到底给多少条路径贡献出了最小值,还真是有点没头绪(在已知的复杂度一看 最多只能用nlogn的),最后是看了解答才知道的 用并查集来解决某个最小

Codeforces 437C The Child and Toy(贪心)

题目连接:Codeforces 437C The Child and Toy 题目大意:孩子有一个玩具,有n个部件组成,m条绳子组成,每条绳子连接两个部件.小孩比较顽皮,要将玩具拆成不可分割的部件,每次剪断一条绳子的代价是该绳子连接的两个部件的权值中较小的值.问说最小的总代价是多少. 解题思路:以为每条边都是要被剪断的,所以将节点按照代价值从大到小排序,每次拿掉权值大的点,与该点连接并且还未剪断的边均用另外点的权值. #include <cstdio> #include <cstring

Codeforces 437E The Child and Polygon(区间DP)

题目链接:Codeforces 437E The Child and Polygon 题目大意:给出一个多边形,问说有多少种分割方法,将多边形分割为多个三角形. 解题思路:首先要理解向量叉积的性质,一开始将给出的点转换成顺时针,然后用区间dp计算.dp[i][j]表示从点i到点j可以有dp[i][j]种切割方法.然后点i和点j是否可以做为切割线,要经过判断,即在i和j中选择的话点k的话,点k要在i,j的逆时针方. #include <cstdio> #include <cstring&g

codeforce 437 D The Child and Zoo

题意:给出n个带权值的点,m条边,任意两点之间的一条路径的权值为这条路径上的所有点中的最小权值,任意两点间的权值为它们之间所有路径的权值中最大的那个. 做法:考虑下并查集,就是首先把所有边降序排序,然后开始建立并查集,若要加入的两点已经在同一个集合中,那么已经贡献到了ans,不用管了,若不在,则进行合并,利用乘法原理也就是两个集合元素数量相乘算出它们之间能够形成多少路径,这些路径的权值就是这两个点的最小权值,然后贡献给ans,不断如此,就可算出答案.还是很有意思的. #include<map>

[CF#250 Div.2 D]The Child and Zoo(并查集)

题目:http://codeforces.com/problemset/problem/437/D 题意:有n个点,m条边的无向图,保证所有点都能互通,n,m<=10^5 每个点都有权值,每条边的权值定义为这条边连接两点的权值中的最小值. f(p,q)表示p到q的路径中边权的最小值,如果有多条路经,就取每条路径最小值中的最小值 要求的就是对于所有1<=p<=n,1<=q<=n,p≠q,f(p,q)的平均值 分析: 刚开始是想考虑每条边对总和的贡献,结果没想通. 一个很巧的办法

CodeForces 438D The Child and Sequence(线段树)

题目:http://codeforces.com/problemset/problem/438/D 一个数取模n%m,有两种情况. 1.m>n, n%m=n; 2.m<=n, n%m<=n/2; 所以当m>n时,取模操作可以忽略. 每个a[i]最多需要log(a[i])次取模操作变为0,因此我们可以对所有取模进行暴力更新.最多要更新n*log(a[i])次,由于单次更新复杂度为log(n),所以总复杂度为n*logn*log(a[i]). #include <bits/std