我们先两次dfs计算出每个点能到达最远点的距离。
暴力计算两棵树x, y连边直径的期望很好求, 我们假设SZ(x) < SZ(y)
我们枚举 x 的每个端点, 二分找到分界点, 复杂度为SZ(x) * log(SZ(y))
其实我们对于每次询问我们记忆化一下就可以啦。
这是因为对于SZ(x)小于 sqrt(n)的询问, 我们直接暴力求就好啦, 复杂度q * SZ(x) * log(SZ(y))
对于SZ(x) > sqrt(n) 这样的 x , 个数绝对不超过sqrt(n)所以如果两两之间的答案全部算出来的
最坏复杂度是sqrt(n) * sqrt(n) / 2 * sqrt(n) * log(n) == n * sqrt(n) * log(n) 。 所以直接记忆化就好啦。
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;} const int B = 330; map<PII, LL> Map; int treecnt, belong[N]; vector<int> tree[N]; vector<LL> sum[N]; int n, m, q, maxdis[N], dia[N], son[N]; vector<int> G[N]; bool root[N]; void dfs(int u, int fa, int idx) { belong[u] = idx; son[idx]++; for(auto& v : G[u]) { if(v == fa) continue; dfs(v, u, idx); chkmax(maxdis[u], maxdis[v] + 1); } } void dfs2(int u, int fa, int maxup) { chkmax(maxdis[u], maxup + 1); int mx0 = maxup, mx1 = -inf; for(auto& v : G[u]) { if(v == fa) continue; if(maxdis[v] > mx0) mx1 = mx0, mx0 = maxdis[v]; else if(maxdis[v] > mx1) mx1 = maxdis[v]; } for(auto& v : G[u]) { if(v == fa) continue; if(maxdis[v] == mx0) dfs2(v, u, mx1 + 1); else dfs2(v, u, mx0 + 1); } } LL calc(int u, int v) { LL ans = 0; LL maxdia = max(dia[u], dia[v]); for(auto& d : tree[u]) { int p = upper_bound(ALL(tree[v]), maxdia - d - 1) - tree[v].begin(); ans += p * maxdia; if(p < SZ(tree[v])) { ans += (SZ(tree[v]) - p) * (d + 1) + sum[v].back(); if(p - 1 >= 0) ans -= sum[v][p - 1]; } } return ans; } int main() { scanf("%d%d%d", &n, &m, &q); for(int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } for(int i = 1; i <= n; i++) if(!belong[i]) dfs(i, 0, ++treecnt), root[i] = true; for(int i = 1; i <= n; i++) if(root[i]) dfs2(i, 0, -1); for(int i = 1; i <= n; i++) { tree[belong[i]].push_back(maxdis[i]); chkmax(dia[belong[i]], maxdis[i]); } for(int i = 1; i <= treecnt; i++) { sort(ALL(tree[i])); sum[i].resize(SZ(tree[i])); sum[i][0] = tree[i][0]; for(int j = 1; j < SZ(sum[i]); j++) sum[i][j] = sum[i][j - 1] + tree[i][j]; } for(int i = 1; i <= q; i++) { int u, v; scanf("%d%d", &u, &v); u = belong[u]; v = belong[v]; if(son[u] > son[v]) swap(u, v); if(u == v) { puts("-1"); } else { if(Map.find(mk(u, v)) == Map.end()) Map[mk(u, v)] = calc(u, v); printf("%.12f\n", 1.0 * Map[mk(u, v)] / son[u] / son[v]); } } return 0; } /* */