Qin Shi Huang's National Road System HDU - 4081

原题链接

  • 题意:遍历每个非关键边,预处理出来两个 \(MST\) 中的点到最近公共祖先的最长的边的距离,然后就是 \(\frac{cnt}{sum - Max_{i,j}}\) 枚举 \(i,j\) 即可,简直就和求最小生成树的过程一模一样。
  • 代码:
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
const int N = 1111;
const int M = 2 * N * N;
int cnt = 0;
double sum = 0;
int h[N], to[M], ne[M], idx;
double W[M];
int dep[N];
int f[N][20];
double g[N][20];
void add(int u, int v ,double w) {
    ne[idx] =h[u], to[idx] = v, W[idx]  =w, h[u] = idx++;
}
void dfs(int u, int fa) {
    if (fa == -1)dep[u] = 1;
    else dep[u] = dep[fa] + 1;
    for (int i = 1; i <= 13; i ++) {
        f[u][i] = f[f[u][i-1]][i-1];
        g[u][i] = max(g[u][i-1],g[f[u][i-1]][i-1]);
    }
    for (int i = h[u]; i!= -1; i = ne[i]) {
        int v = to[i];
        if (dep[v] == 0) {
            f[v][0] = u;
            g[v][0] = W[i];
            dfs(v, u);
        }
    }
    
}
struct node {
    double x, y;
    int cnt;
}p[N];
struct edge {
    int u, v;double w;
    int cnt;
}e[M];
bool cmp(edge a, edge b){return a.w < b.w;}
int fa[N];
int Find(int x){return fa[x] == x?x:fa[x] = Find(fa[x]);}
double dis(node a, node b) {
    return sqrt((a.x- b.x)*(a.x-b.x) + (a.y - b.y) * (a.y - b.y));
}
void un(int i) {
    int fx = Find(e[i].u);
    int fy = Find(e[i].v);
    if (fx == fy)return;
    fa[fx] = fy;
    add(e[i].u, e[i].v, e[i].w);
    add(e[i].v, e[i].u, e[i].w);
    sum += e[i].w;
}
double lca(int u, int v) {
    if (dep[u] < dep[v])swap(u, v);
    double ret = -1;
    for (int i = 14; i >= 0; i--) {
        if (dep[f[u][i]] >= dep[v]) {
            ret = max(ret, g[u][i]);
            u = f[u][i];
        }
    }
    if (u == v)return ret;
    for (int i = 14; i >= 0; i--) {
        if (f[u][i] != f[v][i]) {
            ret = max(ret, max(g[u][i], g[v][i]));
            u = f[u][i], v = f[v][i];
        }
    }
    ret = max(ret, max(g[u][0], g[v][0]));
    return ret;
}
void solve() {
    int n;scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf("%lf%lf%d", &p[i].x, &p[i].y,&p[i].cnt);
        fa[i] = i;
    }
    int m = 0;cnt = 0;
    sum = 0;
    double ans = -1;
    memset(h, -1, sizeof h);idx = 0;
    memset(dep, 0, sizeof dep);
    for (int i = 1; i <= n; i ++) {
        for (int j = i + 1; j <= n; j ++) {
            e[++m] = {i, j, dis(p[i], p[j])};
        }
    }
    sort(e + 1, e + 1 +  m, cmp);
    for (int i = 1; i <= m; i ++) {
        un(i);
    }
    dfs(1, -1);
    for (int i = 1; i <= n; i ++) {
        for (int j = i + 1; j <=n; j ++) {
            ans = max(ans,(double)( p[i].cnt + p[j].cnt*1.0 )/(sum - lca(i, j) ) );
        }
    }
    printf("%.2lf\n", ans);
}
signed main() {
    int t;scanf("%d", &t);
    while (t--) {
        solve();
    }
    return 0;
}
posted @ 2021-04-09 09:18  u_yan  阅读(34)  评论(0编辑  收藏  举报