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

題意:ios

有一個棵樹,如今讓你找兩個點鏈接起來,這樣必然成爲一個環,如今要求這些環長度的指望,也就是平均值。算法

分析:spa

第一次作LCA題,作多校的時候,瞎幾把找了模板敲,敲了個八九不離十,只是姿式不太好,須要考慮不少細節。.net

其實我以爲這題最多隻能算中等題。code

由於一直沒空,寫題解也晚了,已經有不少人寫了題解,都寫的不錯。反正比我厲害。blog

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

 

代碼:string

  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 }
相關文章
相關標籤/搜索