标签:double while += The print etc main opera 好的
这个题还是很好的
有几个套路
先是我们看到题目中让我们处理点权,但是我们发现并不好处理
所以就先化点为边 (套路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;
}
Codeforces 437D The Child and Zoo
标签:double while += The print etc main opera 好的
原文地址:https://www.cnblogs.com/yspm/p/12256494.html