• Codeforces 437D The Child and Zoo


    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

      1 /**
      2  * Codeforces
      3  * Problem#437D
      4  * Accepted
      5  * Time:202ms
      6  * Memory:15452k
      7  */
      8 #include <bits/stdc++.h>
      9 using namespace std;
     10 #define smax(a, b) a = max(a, b)
     11 typedef bool boolean;
     12 
     13 typedef class union_found {
     14     public:
     15         int *f;
     16         
     17         union_found() {        }
     18         union_found(int n) {
     19             f = new int[(n + 1)];
     20             for(int i = 1; i <= n; i++)
     21                 f[i] = i;
     22         }
     23         
     24         int find(int x) {
     25             return (f[x] == x) ? (x) : (f[x] = find(f[x]));
     26         }
     27         
     28         void unit(int fa, int so) {
     29             int ffa = find(fa);
     30             int fso = find(so);
     31             f[fso] = ffa;
     32         }
     33         
     34         boolean isConnected(int a, int b) {
     35             return find(a) == find(b);
     36         }
     37 }union_found; 
     38 
     39 typedef class Edge1 {
     40     public:
     41         int u;
     42         int v;
     43         int w;
     44         
     45         boolean operator < (Edge1 b) const {
     46             return w > b.w;
     47         }
     48 }Edge1;
     49 
     50 int n, m;
     51 int *vals;
     52 Edge1* es;
     53 union_found uf;
     54 vector<int> *g;
     55 
     56 inline void init() {
     57     scanf("%d%d", &n, &m);
     58     vals = new int[(n + 1)];
     59     es = new Edge1[(m + 1)];
     60     g = new vector<int>[(n + 1)];
     61     for(int i = 1; i <= n; i++)
     62         scanf("%d", vals + i);
     63     for(int i = 1; i <= m; i++)
     64         scanf("%d%d", &es[i].u, &es[i].v), es[i].w = min(vals[es[i].u], vals[es[i].v]);
     65 }
     66 
     67 boolean *vis;
     68 int *siz;
     69 long long sum = 0;
     70 void tree_dp(int node, int fa) {
     71     siz[node] = 1;
     72     for(int i = 0; i < (signed)g[node].size(); i++) {
     73         int& e = g[node][i];
     74         if(e == fa || vis[e])    continue;
     75         tree_dp(e, node);
     76         siz[node] += siz[e];
     77     }
     78 }
     79 
     80 void getG(int node, int fa, int all, int& mins, int& G) {
     81     int msiz = 1;
     82     for(int i = 0; i < (signed)g[node].size(); i++) {
     83         int& e = g[node][i];
     84         if(e == fa || vis[e])    continue;
     85         getG(e, node, all, mins, G);
     86         smax(msiz, siz[e]);
     87     }
     88     smax(msiz, all - siz[node]);
     89     if(msiz < mins)    mins = msiz, G = node;
     90 }
     91 
     92 int cnt;
     93 int* dis;
     94 void dfs(int node, int fa, int d) {
     95     dis[++cnt] = d;
     96 //    printf("%d: %d
    ", node, d);
     97     for(int i = 0; i < (signed)g[node].size(); i++) {
     98         int& e = g[node][i];
     99         if(e == fa || vis[e])    continue;
    100         dfs(e, node, min(d, vals[e]));
    101     }
    102 }
    103 
    104 long long calc(int l, int r, int lim) {
    105     long long rt = 0;
    106     sort(dis + l, dis + r + 1);
    107     for(int i = l; i <= r; i++) {
    108         rt += (r - i) * 1LL * min(dis[i], lim);
    109 //        printf("%d %d %d %d %d
    ", l, r, i, dis[i], rt);
    110     }
    111     return rt;
    112 }
    113 
    114 void dividing(int node) {
    115     int mins = 23333333, G;
    116     tree_dp(node, 0);
    117     if(siz[node] == 1)    return;
    118     getG(node, 0, siz[node], mins, G);
    119 //    cout << G << endl; 
    120     cnt = 0;
    121     vis[G] = true;
    122     for(int i = 0, l; i < (signed)g[G].size(); i++) {
    123         int& e = g[G][i];
    124         if(vis[e])    continue;
    125         l = cnt;
    126         dfs(e, G, vals[e]);
    127 //        cout << l << " " << e << " " << cnt << endl;
    128         sum -= calc(l + 1, cnt, vals[G]);
    129 //        cout << cnt << endl;
    130     }
    131     dis[++cnt] = vals[G];
    132     sum += calc(1, cnt, vals[G]);
    133 //    cout << sum << endl;
    134     for(int i = 0, l; i < (signed)g[G].size(); i++) {
    135         int& e = g[G][i];
    136         if(vis[e])    continue;
    137         dividing(g[G][i]);
    138     }
    139 }
    140 
    141 inline void solve() {
    142     sort(es + 1, es + m + 1);
    143     uf = union_found(n);
    144     int fin = 1;
    145     for(int i = 1; i <= m && fin < n; i++) {
    146         if(!uf.isConnected(es[i].u, es[i].v)) {
    147             uf.unit(es[i].u, es[i].v);
    148             g[es[i].u].push_back(es[i].v);
    149             g[es[i].v].push_back(es[i].u);
    150 //            printf("connect %d %d
    ", es[i].u, es[i].v);
    151             fin++;
    152         }
    153     }
    154     vis = new boolean[(n + 1)];
    155     siz = new int[(n + 1)];
    156     dis = new int[(n + 1)];
    157     memset(vis, false, sizeof(boolean) * (n + 1));
    158     dividing(1);
    159     long long c = n * 1LL * (n - 1);
    160     printf("%.9lf", (sum << 1) * 1.0 / c);
    161 }
    162 
    163 int main() {
    164     init();
    165     solve();
    166     return 0;
    167 }
    The Child and Zoo(Point Division)

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

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

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

    Code

     1 /**
     2  * Codeforces
     3  * Problem#437D
     4  * Accepted
     5  * Time: 62ms
     6  * Memory: 4408k
     7  */ 
     8 #include <bits/stdc++.h>
     9 using namespace std;
    10 typedef bool boolean;
    11 
    12 typedef class union_found {
    13     public:
    14         int *f;
    15         int *s;
    16         
    17         union_found() {        }
    18         union_found(int n) {
    19             f = new int[(n + 1)];
    20             s = new int[(n + 1)];
    21             for(int i = 1; i <= n; i++)
    22                 f[i] = i, s[i] = 1;
    23         }
    24         
    25         int find(int x) {
    26             return (f[x] == x) ? (x) : (f[x] = find(f[x]));
    27         }
    28         
    29         void unit(int fa, int so) {
    30             int ffa = find(fa);
    31             int fso = find(so);
    32             f[fso] = ffa;
    33             s[ffa] += s[fso];
    34         }
    35         
    36         boolean isConnected(int a, int b) {
    37             return find(a) == find(b);
    38         }
    39 }union_found; 
    40 
    41 typedef class Edge {
    42     public:
    43         int u;
    44         int v;
    45         int w;
    46         
    47         boolean operator < (Edge b) const {
    48             return w > b.w;
    49         }
    50 }Edge;
    51 
    52 int n, m;
    53 int *vals;
    54 Edge* es;
    55 union_found uf;
    56 
    57 inline void init() {
    58     scanf("%d%d", &n, &m);
    59     vals = new int[(n + 1)];
    60     es = new Edge[(m + 1)];
    61     for(int i = 1; i <= n; i++)
    62         scanf("%d", vals + i);
    63     for(int i = 1; i <= m; i++)
    64         scanf("%d%d", &es[i].u, &es[i].v), es[i].w = min(vals[es[i].u], vals[es[i].v]);
    65 }
    66 
    67 long long sum = 0;
    68 inline void solve() {
    69     sort(es + 1, es + m + 1);
    70     uf = union_found(n);
    71     int fin = 1;
    72     for(int i = 1; i <= m && fin < n; i++) {
    73         if(!uf.isConnected(es[i].u, es[i].v)) {
    74             sum += uf.s[uf.find(es[i].u)] * 1LL * uf.s[uf.find(es[i].v)] * es[i].w;
    75             uf.unit(es[i].u, es[i].v);
    76             fin++;
    77         }
    78     }
    79     long long c = n * 1LL * (n - 1);
    80     printf("%.9lf", (sum << 1) * 1.0 / c);
    81 }
    82 
    83 int main() {
    84     init();
    85     solve();
    86     return 0;
    87 }
  • 相关阅读:
    ASP.NET Core 中文文档 第四章 MVC(3.2)Razor 语法参考
    ASP.NET Core 中文文档 第四章 MVC(3.1)视图概述
    ASP.NET Core 中文文档 第四章 MVC(2.3)格式化响应数据
    ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证
    ASP.NET Core 中文文档 第四章 MVC(2.1)模型绑定
    ASP.NET Core 中文文档 第四章 MVC(01)ASP.NET Core MVC 概览
    mysql 解除正在死锁的状态
    基于原生JS的jsonp方法的实现
    HTML 如何显示英文单、双引号
    win2008 r2 服务器php+mysql+sqlserver2008运行环境配置(从安装、优化、安全等)
  • 原文地址:https://www.cnblogs.com/yyf0309/p/7290041.html
Copyright © 2020-2023  润新知