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

题意:

有一个棵树,现在让你找两个点连接起来,这样必然成为一个环,现在要求这些环长度的期望,也就是平均值。

分析:

第一次做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 }

 

posted @ 2017-05-20 17:59  tak_fate  阅读(210)  评论(0编辑  收藏  举报