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

来源:互联网 发布:淘宝开放平台sdk下载 编辑:程序博客网 时间:2024/06/01 09:19

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 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 ≤ 1050 ≤ 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 ≤ nxi ≠ yi), denoting the road between areas xiand 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.

Sample test(s)
input
4 310 20 30 401 32 34 3
output
16.666667
input
3 310 20 301 22 33 1
output
13.333333
input
7 840 20 10 30 20 50 401 22 33 44 55 66 71 45 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 .


大致题意:

n,m1e5 的点权无向图,定义F(u,v) 表示,所有u从v的  |  路径中经过的点权的最小值 |  的最大值

求所有点对的F之和的平均值 (u!=v) sigmaF(u,v)/ n*(n-1)


这种类似的问题很多,涉及到区间的最大值,最小值用单调栈解决的问题,大部分可以用排序后加并查集解决


方法一:

这题也是一样的思想,对点权从大到小排序后 ,当处理到当前点时,前面已经处理过点且与它相连的点毕竟要经过它相互连接,所以这些点的F值就是这个点权的值,这就相当于,规定了一个构图的顺序进行构图,这样可以O(1)算出每个点间的F值。


//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <cstring>#include <cmath>#include <queue>#include <stack>#include <map>#include <set>#include <string>#include <vector>#include <cstdio>#include <ctime>#include <bitset>#include <algorithm>#define SZ(x) ((int)(x).size())#define ALL(v) (v).begin(), (v).end()#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)#define REP(i,n) for ( int i=1; i<=int(n); i++ )using namespace std;typedef long long ll;#define X first#define Y secondtypedef pair<ll,ll> pii;template <class T>inline bool RD(T &ret) {char c; int sgn;if (c = getchar(), c == EOF) return 0;while (c != '-' && (c<'0' || c>'9')) c = getchar();sgn = (c == '-') ? -1 : 1;ret = (c == '-') ? 0 : (c - '0');while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');ret *= sgn;return 1;}template <class T>inline void PT(T x) {if (x < 0) {putchar('-');x = -x;}if (x > 9) pt(x / 10);putchar(x % 10 + '0');}const int N = 1e5+100;const int M = 4*N;int ecnt;int head[N];struct Edge{        int v,nxt;        Edge(int v = 0,int nxt = 0) : v(v),nxt(nxt){}}es[M];pii poi[N];bool vis[N];int n,m;inline void add_edge(int u,int v){        es[ecnt] = Edge(v,head[u]);        head[u] = ecnt++;        es[ecnt] = Edge(u,head[v]);        head[v] = ecnt++;}ll val[N];int sz[N];int fa[N];int getf(int x){        return x == fa[x] ? x : fa[x] = getf(fa[x]);}void Merge(int u,int v){        int f1 = getf(u) , f2 = getf(v);        if( f1 == f2) return ;        fa[f1] = f2;        sz[f2] += sz[f1];}int main(){        memset(head,-1,sizeof(head));        cin>>n>>m;        REP(i,n) fa[i] = i,sz[i] = 1;        REP(i,n) {                RD(poi[i].X);                poi[i].Y = i;                val[i] = poi[i].X;        }        REP(i,m){                int u,v;                RD(u),RD(v);                add_edge(u,v);        }        sort(poi+1,poi+1+n);        ll ans = 0;        for(int k = n ; k >= 1; k--){                int u = poi[k].Y;                vis[u] = 1;                ll sum = 1;                vector<ll> tmp;//与它相邻的点连通块                tmp.push_back(1);                for(int i = head[u];~i ; i = es[i].nxt){                        int v = es[i].v;                        if( vis[v] == 0) continue;                        if( getf(v) == getf(u) ) continue;                        int f = getf(v);                        sum += sz[f];                        tmp.push_back(sz[f]);                        Merge(u,v);                }                foreach(it,tmp){                        ans += (sum-*it)*(*it)*val[u];                }                tmp.clear();        }        double res = (double)ans/( (double)n*(n-1) );        printf("%.9f\n",res);}



方法二:

还有一个稍微聪明点的方法,不是以点权排序,以边权排序,这样需要先给个边权的定义,是此边连接的两点中点权最小值。

这样以边权从大到小排序,当处理到此边权以后,此边相连的只有两个连通块,这两个连通块中当前在并查集中的点的点对F就是此边权的值,这样就两个连通块,好处理一些

和方法一的道理是一样的

//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <cstring>#include <cmath>#include <queue>#include <stack>#include <map>#include <set>#include <string>#include <vector>#include <cstdio>#include <ctime>#include <bitset>#include <algorithm>#define SZ(x) ((int)(x).size())#define ALL(v) (v).begin(), (v).end()#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)#define REP(i,n) for ( int i=1; i<=int(n); i++ )using namespace std;typedef long long ll;#define X first#define Y secondtypedef pair<int,int> pii;template <class T>inline bool RD(T &ret) {        char c; int sgn;        if (c = getchar(), c == EOF) return 0;        while (c != '-' && (c<'0' || c>'9')) c = getchar();        sgn = (c == '-') ? -1 : 1;        ret = (c == '-') ? 0 : (c - '0');        while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');        ret *= sgn;        return 1;}template <class T>inline void PT(T x){        if (x < 0) {                putchar('-');                x = -x;        }        if (x > 9) pt(x / 10);        putchar(x % 10 + '0');}const int N = 1e5+100;const int M = 2*N;int ecnt;struct Edge{        int u,v,w ;        Edge(int u = 0,int v = 0,int w = 0):u(u),v(v),w(w){}}es[M];int n,m;int val[N];bool cmp(const Edge &a,const Edge&b){        return a.w > b.w;}ll ans = 0;int fa[N],sz[N];int getf(int x){        return x == fa[x] ? x:fa[x] = getf(fa[x]);}void Merge(int u,int v,int w){        int f1 = getf(u), f2 = getf(v);        ans += (ll)w*sz[f1]*sz[f2];        fa[f1] = f2;        sz[f2] += sz[f1];}int main(){        cin>>n>>m;        REP(i,n) fa[i] = i,sz[i] = 1;        REP(i,n) RD(val[i]);        REP(i,m){                int u,v;                RD(u),RD(v);                es[++ecnt] = Edge(u,v,min(val[u],val[v]));        }        sort(es+1,es+1+ecnt,cmp);        REP(i,ecnt){                int u =  es[i].u , v = es[i].v ,w = es[i].w;                if( getf(u) == getf(v)) continue;                Merge(u,v,w);        }        double res = (double)2*ans/((double)n*(n-1));        printf("%.9f\n",res);}


0 0
原创粉丝点击