• (树形dp+LCA倍增法)CSU 1915


    题意:

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

    分析:

    第一次做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
    ", 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
    ", tolen * 1.0 / sum);
    131             }
    132 
    133 
    134         }
    135 
    136     }
    137     return 0;
    138 
    139 }
  • 相关阅读:
    逆向学习中扫雷第一阶段小结
    破解基础篇三
    逆向方面学习实践安排
    破解基础篇二
    20159320《网络攻防实践》第9周视频总结
    20159320《网络攻防实践》第9周学习总结
    20159320《网络攻防实践》第9周教材总结
    破解基础篇之第一部分
    20159320《网络攻防实践》第8周视频总结
    20159320《网络攻防实践》第8周学习总结
  • 原文地址:https://www.cnblogs.com/tak-fate/p/6882759.html
Copyright © 2020-2023  润新知