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 ai animals in it. Also there are m roads in the zoo, and each road connects two distinct areas. Naturally the zoo is connected, so you can reach any area of the zoo from any other area using the roads.

Our child is very smart. Imagine the child want to go from area p to area q. Firstly he considers all the simple routes from p to q. For each route the child writes down the number, that is equal to the minimum number of animals among the route areas. Let's denote the largest of the written numbers as f(p, q). Finally, the child chooses one of the routes for which he writes down the value f(p, q).

After the child has visited the zoo, he thinks about the question: what is the average value of f(p, q) for all pairs p, q (p ≠ q)? Can you answer his question?

Input

The first line contains two integers n and m (2 ≤ n ≤ 105; 0 ≤ m ≤ 105). The second line contains n integers: a1, a2, ..., an (0 ≤ ai ≤ 105). Then follow m lines, each line contains two integers xi and yi (1 ≤ xi, yi ≤ n; xi ≠ yi), denoting the road between areas xi and yi.

All roads are bidirectional, each pair of areas is connected by at most one road.

Output

Output a real number — the value of .

The answer will be considered correct if its relative or absolute error doesn't exceed 10 - 4.

Examples
Input
4 3
10 20 30 40
1 3
2 3
4 3
Output
16.666667
Input
3 3
10 20 30
1 2
2 3
3 1
Output
13.333333
Input
7 8
40 20 10 30 20 50 40
1 2
2 3
3 4
4 5
5 6
6 7
1 4
5 7
Output
18.571429
Note

Consider the first sample. There are 12 possible situations:

  • p = 1, q = 3, f(p, q) = 10.
  • p = 2, q = 3, f(p, q) = 20.
  • p = 4, q = 3, f(p, q) = 30.
  • p = 1, q = 2, f(p, q) = 10.
  • p = 2, q = 4, f(p, q) = 20.
  • p = 4, q = 1, f(p, q) = 10.

Another 6 cases are symmetrical to the above. The average is .

Consider the second sample. There are 6 possible situations:

  • p = 1, q = 2, f(p, q) = 10.
  • p = 2, q = 3, f(p, q) = 20.
  • p = 1, q = 3, f(p, q) = 10.

Another 3 cases are symmetrical to the above. The average is .


  (Tag好像很吓人的样子,不过这个是两个解法的Tag取并)

  题目大意 定义一条路径的权为这条路径所有经过点的点权的最小值,无向连通图中任意不同的两点的"距离"为这两点间所有简单路径中最大的权。给定一个无向连通图,求它的任意不同的两点间的"距离"的平均值。

  显然你需要求出任意不同的两点间"距离"的和,所以你需要在图上进行路径统计。

  然而表示并不会,所以我们先把问题放在树上,然后再考虑推广到图上。

  对于树上路径统计的问题常用算(套)法(路)->树分治。由于不会边分只会点分,所以现在考虑计算经过重心的所有路径的权和。

  根据常用点分套路,肯定需要计算每个子树中每个点到这个子树的根的"距离",然后对当前分治的树进行统计,然后减去每个子树内部的不合法路径(不是简单路径)。

  这个统计很简单,你只需排个序,然后你就可以知道每个点到哪些点的"距离"是自己到所在子树的根的"距离"。

  于是便可以在的时间内水掉这个子任务。

  现在考虑推广的问题(其实这也不算推广吧。。反向搜索比较合适吧)。仔细看题,然后用贪心的思想你可以得到一个结论:任意两个不同点之间的最优路径一定在最大生成树上。

  所以你只需要用Kruskal先建出最大生成树(边权是它连接的两个点的点权的最小值),然后再进行点分治就好了。(下面是编程复杂度的点分治的代码)

Code

 /**
* Codeforces
* Problem#437D
* Accepted
* Time:202ms
* Memory:15452k
*/
#include <bits/stdc++.h>
using namespace std;
#define smax(a, b) a = max(a, b)
typedef bool boolean; typedef class union_found {
public:
int *f; union_found() { }
union_found(int n) {
f = new int[(n + )];
for(int i = ; i <= n; i++)
f[i] = i;
} int find(int x) {
return (f[x] == x) ? (x) : (f[x] = find(f[x]));
} void unit(int fa, int so) {
int ffa = find(fa);
int fso = find(so);
f[fso] = ffa;
} boolean isConnected(int a, int b) {
return find(a) == find(b);
}
}union_found; typedef class Edge1 {
public:
int u;
int v;
int w; boolean operator < (Edge1 b) const {
return w > b.w;
}
}Edge1; int n, m;
int *vals;
Edge1* es;
union_found uf;
vector<int> *g; inline void init() {
scanf("%d%d", &n, &m);
vals = new int[(n + )];
es = new Edge1[(m + )];
g = new vector<int>[(n + )];
for(int i = ; i <= n; i++)
scanf("%d", vals + i);
for(int i = ; i <= m; i++)
scanf("%d%d", &es[i].u, &es[i].v), es[i].w = min(vals[es[i].u], vals[es[i].v]);
} boolean *vis;
int *siz;
long long sum = ;
void tree_dp(int node, int fa) {
siz[node] = ;
for(int i = ; i < (signed)g[node].size(); i++) {
int& e = g[node][i];
if(e == fa || vis[e]) continue;
tree_dp(e, node);
siz[node] += siz[e];
}
} void getG(int node, int fa, int all, int& mins, int& G) {
int msiz = ;
for(int i = ; i < (signed)g[node].size(); i++) {
int& e = g[node][i];
if(e == fa || vis[e]) continue;
getG(e, node, all, mins, G);
smax(msiz, siz[e]);
}
smax(msiz, all - siz[node]);
if(msiz < mins) mins = msiz, G = node;
} int cnt;
int* dis;
void dfs(int node, int fa, int d) {
dis[++cnt] = d;
// printf("%d: %d\n", node, d);
for(int i = ; i < (signed)g[node].size(); i++) {
int& e = g[node][i];
if(e == fa || vis[e]) continue;
dfs(e, node, min(d, vals[e]));
}
} long long calc(int l, int r, int lim) {
long long rt = ;
sort(dis + l, dis + r + );
for(int i = l; i <= r; i++) {
rt += (r - i) * 1LL * min(dis[i], lim);
// printf("%d %d %d %d %d\n", l, r, i, dis[i], rt);
}
return rt;
} void dividing(int node) {
int mins = , G;
tree_dp(node, );
if(siz[node] == ) return;
getG(node, , siz[node], mins, G);
// cout << G << endl;
cnt = ;
vis[G] = true;
for(int i = , l; i < (signed)g[G].size(); i++) {
int& e = g[G][i];
if(vis[e]) continue;
l = cnt;
dfs(e, G, vals[e]);
// cout << l << " " << e << " " << cnt << endl;
sum -= calc(l + , cnt, vals[G]);
// cout << cnt << endl;
}
dis[++cnt] = vals[G];
sum += calc(, cnt, vals[G]);
// cout << sum << endl;
for(int i = , l; i < (signed)g[G].size(); i++) {
int& e = g[G][i];
if(vis[e]) continue;
dividing(g[G][i]);
}
} inline void solve() {
sort(es + , es + m + );
uf = union_found(n);
int fin = ;
for(int i = ; i <= m && fin < n; i++) {
if(!uf.isConnected(es[i].u, es[i].v)) {
uf.unit(es[i].u, es[i].v);
g[es[i].u].push_back(es[i].v);
g[es[i].v].push_back(es[i].u);
// printf("connect %d %d\n", es[i].u, es[i].v);
fin++;
}
}
vis = new boolean[(n + )];
siz = new int[(n + )];
dis = new int[(n + )];
memset(vis, false, sizeof(boolean) * (n + ));
dividing();
long long c = n * 1LL * (n - );
printf("%.9lf", (sum << ) * 1.0 / c);
} int main() {
init();
solve();
return ;
}

The Child and Zoo(Point Division)

  不得不说贪心世界博大精深。下面将用一个神奇的贪心将时间复杂度去掉一个log。

  在跑最大生成树的时候其实就可以直接出答案了。对于一条边将两个原本不连通的连通块连接起来,因为是第一次连接,所以这条边在最大生成树上,这条边对总和有贡献。那么会贡献多少次呢?乘法原理算一算,就是两边点数的乘积(两个联通块内的边的权值都比它大,所以一个点在其中的一个联通块中,另一个点在另外一个联通块中,它们的"距离"就是这条边的权值)。

  于是编程复杂度成功下降到O(能1a)。

Code

 /**
* Codeforces
* Problem#437D
* Accepted
* Time: 62ms
* Memory: 4408k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; typedef class union_found {
public:
int *f;
int *s; union_found() { }
union_found(int n) {
f = new int[(n + )];
s = new int[(n + )];
for(int i = ; i <= n; i++)
f[i] = i, s[i] = ;
} int find(int x) {
return (f[x] == x) ? (x) : (f[x] = find(f[x]));
} void unit(int fa, int so) {
int ffa = find(fa);
int fso = find(so);
f[fso] = ffa;
s[ffa] += s[fso];
} boolean isConnected(int a, int b) {
return find(a) == find(b);
}
}union_found; typedef class Edge {
public:
int u;
int v;
int w; boolean operator < (Edge b) const {
return w > b.w;
}
}Edge; int n, m;
int *vals;
Edge* es;
union_found uf; inline void init() {
scanf("%d%d", &n, &m);
vals = new int[(n + )];
es = new Edge[(m + )];
for(int i = ; i <= n; i++)
scanf("%d", vals + i);
for(int i = ; i <= m; i++)
scanf("%d%d", &es[i].u, &es[i].v), es[i].w = min(vals[es[i].u], vals[es[i].v]);
} long long sum = ;
inline void solve() {
sort(es + , es + m + );
uf = union_found(n);
int fin = ;
for(int i = ; i <= m && fin < n; i++) {
if(!uf.isConnected(es[i].u, es[i].v)) {
sum += uf.s[uf.find(es[i].u)] * 1LL * uf.s[uf.find(es[i].v)] * es[i].w;
uf.unit(es[i].u, es[i].v);
fin++;
}
}
long long c = n * 1LL * (n - );
printf("%.9lf", (sum << ) * 1.0 / c);
} int main() {
init();
solve();
return ;
}

Codeforces 437D The Child and Zoo - 树分治 - 贪心 - 并查集 - 最大生成树的更多相关文章

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

    题目链接:Codeforces 437D The Child and Zoo 题目大意:小孩子去參观动物园,动物园分非常多个区,每一个区有若干种动物,拥有的动物种数作为该区的权值.然后有m条路,每条路 ...

  2. Codeforces 437D The Child and Zoo(并查集)

    Codeforces 437D The Child and Zoo 题目大意: 有一张连通图,每个点有对应的值.定义从p点走向q点的其中一条路径的花费为途径点的最小值.定义f(p,q)为从点p走向点q ...

  3. 【BZOJ4025】二分图(线段树分治,并查集)

    [BZOJ4025]二分图(线段树分治,并查集) 题面 BZOJ 题解 是一个二分图,等价于不存在奇环. 那么直接线段树分治,用并查集维护到达根节点的距离,只计算就好了. #include<io ...

  4. 【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)

    [CF938G]Shortest Path Queries(线段树分治,并查集,线性基) 题面 CF 洛谷 题解 吼题啊. 对于每个边,我们用一个\(map\)维护它出现的时间, 发现询问单点,边的出 ...

  5. codeforces 437D The Child and Zoo

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  6. Dash Speed【好题,分治,并查集按秩合并】

    Dash Speed Online Judge:NOIP2016十联测,Claris#2 T3 Label:好题,分治,并查集按秩合并,LCA 题目描述 比特山是比特镇的飙车圣地.在比特山上一共有 n ...

  7. [BZOJ3038]上帝造题的七分钟2 树状数组+并查集

    考试的时候用了两个树状数组去优化,暴力修改,树状数组维护修改后区间差值还有最终求和,最后骗了40分.. 这道题有好多种做法,求和好说,最主要的是开方.这道题过的关键就是掌握一点:在数据范围内,最多开方 ...

  8. hdu 5458 Stability(树链剖分+并查集)

    Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total ...

  9. 【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目描述 给你 $n$ 个点,支持 $m$ 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林:询问一个点能到达的最远的点与该点的距离.强制在线. $n\le 3\times 10^5$ ,$ ...

随机推荐

  1. C++ 类定义

    C++ 类定义 定义一个类,本质上是定义一个数据类型的蓝图.这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作. 类定义是 ...

  2. 用log4net记录日志信息

    在.net中用log4net记录日志信息,已经是很平常的事情了. log4net下载:http://logging.apache.org/log4net/download_log4net.cgi 百度 ...

  3. JS怎么控制input框的背景颜色

    $("input").css("background-color","red"); 参考:https://zhidao.baidu.com/ ...

  4. webpack使用三

    Webpack的强大功能 生成Source Maps(使调试更容易) 开发总是离不开调试,方便的调试能极大的提高开发效率,不过有时候通过打包后的文件,你是不容易找到出错了的地方,对应的你写的代码的位置 ...

  5. SQL 跟据出生日期求年龄

    最近做项目时遇到一个问题. 跟据人员的生日与当前日期进行比较求出该人员实际年龄.这个看上去比较简单的问题,其实不细心去看也会有很多问题. 先看第一种: 一张人员信息表里有一人生日(Birthday)列 ...

  6. Hello py

    https://www.cnblogs.com/AdaminXie/p/8339863.html https://www.cnblogs.com/-clq/p/8340515.html https:/ ...

  7. const_cast, dynamic_cast, static_cast,reinterpret_cast

    一.const_cast:用于移除const数据,目标数据类型必须与原类型相同 二.dynamic_cast:用于在两个不同类型之间进行强制转换并且在执行运行时检查它.保证它的合法性,如果在两个互相矛 ...

  8. Django框架----命名URL和URL反向解析

    在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等).人们强烈希望不要硬编码这些URL(费 ...

  9. Charles 从入门到精通 --转

    文章目录 1. 目录及更新说明 2. Charles 限时优惠 3. 简介 4. 安装 Charles 5. 将 Charles 设置成系统代理 6. Charles 主界面介绍 7. 过滤网络请求 ...

  10. vue 生命周期钩子的理解 watch computed

    一  理解vue的生命周期,首先需要注意几个关键字 1. el :选择器 2. $el:对应选择器的template模板(html代码) 3. render:也是vue实例中的一项,其参数更接近vue ...