1. 程式人生 > >(樹形dp+LCA倍增法)CSU 1915 - John and his farm

(樹形dp+LCA倍增法)CSU 1915 - John and his farm

const http 題解 def iostream clu algo farm john

題意:

有一個棵樹,現在讓你找兩個點連接起來,這樣必然成為一個環,現在要求這些環長度的期望,也就是平均值。

分析:

第一次做LCA題,做多校的時候,瞎幾把找了模板敲,敲了個八九不離十,只是姿勢不太好,需要考慮很多細節。

其實我覺得這題最多只能算中等題。

因為一直沒空,寫題解也晚了,已經有很多人寫了題解,都寫的不錯。反正比我厲害。

這題用倍增法比較好一些,因為會用到關鍵點,也就是當v和u處在同一棵子樹中時,找到更高點的下面那個點,倍增法通過深度跳躍可以很快找到。處理起來比其他兩個LCA算法都方便。

代碼:

  1 #include <cstdio>
  2
#include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 #include <map> 7 #include <queue> 8 9 10 using namespace std; 11 12 const int inf = 0x3f3f3f3f; 13 const int maxn = 100010; 14 const int DEG = 20; 15
16 #define fi first 17 #define se second 18 19 typedef long long ll; 20 21 vector<int> g[maxn]; 22 23 int fa[maxn][DEG]; 24 int deg[maxn]; 25 26 int n, q; 27 int u, v; 28 29 void bfs(int root) { 30 queue<int> q; 31 deg[root] = 0; 32 fa[root][0
] = root; 33 q.push(root); 34 while(!q.empty()) { 35 int tmp = q.front(); 36 q.pop(); 37 for(int i = 1; i < DEG; i++) { 38 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 39 } 40 for(int i = 0; i < g[tmp].size(); i++) { 41 int v = g[tmp][i]; 42 if(v == fa[tmp][0])continue; 43 deg[v] = deg[tmp] + 1; 44 fa[v][0] = tmp; 45 q.push(v); 46 } 47 } 48 } 49 50 int LCA(int u, int v) { 51 if(deg[u] > deg[v])swap(u, v); 52 for(int det = deg[v] - deg[u], i = 0; det; det >>= 1, i++) { 53 if(det & 1)v = fa[v][i]; 54 } 55 if(u == v)return u; 56 for(int i = DEG - 1; i >= 0; i--) { 57 if(fa[u][i] != fa[v][i]) { 58 u = fa[u][i]; 59 v = fa[v][i]; 60 } 61 } 62 return fa[u][0]; 63 } 64 65 int len[maxn][2]; 66 int son[maxn]; 67 68 void dfs1(int u, int pre) { 69 son[u] = 1; 70 for(int i = 0; i < g[u].size(); i++) { 71 int v = g[u][i]; 72 if(v == pre)continue; 73 dfs1(v, u); 74 son[u] += son[v]; 75 len[u][0] += len[v][0] + son[v]; 76 } 77 len[u][1] = len[u][0]; 78 } 79 80 void dfs2(int u, int pre) { 81 for(int i = 0; i < g[u].size(); i++) { 82 int v = g[u][i]; 83 if(v == pre)continue; 84 len[v][1] += (len[u][1] - len[v][0] - son[v] + n - son[v]); 85 dfs2(v, u); 86 } 87 } 88 89 int up(int x, int step) { 90 for(int i = 0; i < DEG; i++) { 91 if(step & (1 << i))x = fa[x][i]; 92 } 93 return x; 94 } 95 96 void init() { 97 memset(len, 0, sizeof(len)); 98 memset(son, 0, sizeof(son)); 99 for(int i = 0; i < maxn; i++)g[i].clear(); 100 } 101 102 103 104 105 int main() { 106 while(~scanf("%d%d", &n, &q)) { 107 init(); 108 for(int i = 0; i < n - 1; i++) { 109 scanf("%d%d", &u, &v); 110 g[u].push_back(v); 111 g[v].push_back(u); 112 } 113 bfs(1); 114 dfs1(1, 1); 115 dfs2(1, 1); 116 117 while(q--) { 118 scanf("%d%d", &u, &v); 119 if(deg[u] < deg[v])swap(u, v); 120 int f = LCA(u, v); 121 int dis = deg[u] + deg[v] - deg[f] * 2; 122 if(f == v) { 123 int core = up(u, deg[u] - deg[v] - 1); 124 ll sum = (ll)son[u] * (n - son[core]); 125 ll tolen = (ll)len[u][0] * (n - son[core]) + (ll)(len[v][1] - len[core][0] - son[core]) * son[u] + (ll)dis * sum + sum; 126 printf("%f\n", tolen * 1.0 / sum); 127 } else { 128 ll sum = (ll)son[v] * son[u]; 129 ll tolen = (ll)len[v][0] * son[u] + (ll)len[u][0] * son[v] + (ll)sum * dis + sum; 130 printf("%f\n", tolen * 1.0 / sum); 131 } 132 133 134 } 135 136 } 137 return 0; 138 139 }

(樹形dp+LCA倍增法)CSU 1915 - John and his farm