zoukankan      html  css  js  c++  java
  • 【Cf Edu #47 F】Dominant Indices(长链剖分)

    要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来。

    参考重链剖分,由于一个点向上最多只有$log$条轻边,故每个点最多被合并$log$次。但这不是这题想说的。

    由于我们只保留以深度为下标的信息,重链剖分就会多算,以此引出长链剖分,权且作为一个模板来学习。

    长链剖分时,每个点以最深的儿子作为长儿子,其余为短儿子。

    每个点$O(1)$继承长儿子的信息,将短儿子的信息合并上来。每个点只有作为短儿子时才保留以它为链头的一条长链上的信息,空间复杂度为$O(链长)$。

    显然,每次短儿子被合并之后就不会再被访问到了,因为它合并到了一条比它更长的链,而所有的长链都不相交,每条链都以$O(链长)$被合并掉,故总复杂度是$O(n)$的。

    这道题只要维护深度为$i$的节点的数量,取最大值即可。

    $igodot$技巧&套路:

    • 以深度为下标的信息,可以考虑长链剖分。
    • 通常信息的合并,DSU on tree就可以了。
     1 #include <cstdio>
     2 #include <vector>
     3 
     4 const int N = 1000005;
     5 
     6 int n, hig[N], res[N], son[N], dep[N];
     7 std::vector<int> g[N];
     8 
     9 int yun, las[N], to[N << 1], pre[N << 1];
    10 inline void Add(int a, int b) {
    11     to[++yun] = b; pre[yun] = las[a]; las[a] = yun;
    12 }
    13 
    14 void Dfs(int x, int Fa) {
    15     for (int i = las[x]; i; i = pre[i]) if (to[i] != Fa) {
    16         Dfs(to[i], x);
    17         if (hig[x] < hig[to[i]] + 1) {
    18             hig[x] = hig[to[i]] + 1;
    19             son[x] = to[i];
    20         }
    21     }
    22     if (!son[x]) {
    23         g[x].push_back(1); return;
    24     }
    25     std::swap(g[x], g[son[x]]);
    26     res[x] = res[son[x]];
    27     for (int i = las[x]; i; i = pre[i]) if (to[i] != Fa) {
    28         if (son[x] != to[i]) {
    29             int nx = (int)g[x].size(), nt = (int)g[to[i]].size();
    30             for (int j = 0; j < nt; ++j) {
    31                 g[x][nx - nt + j] += g[to[i]][j];
    32                 if (g[x][nx - nt + j] >= g[x][res[x]]) res[x] = nx - nt + j;
    33             }
    34         }
    35     }
    36     g[x].push_back(1);
    37     if (g[x][res[x]] == 1) res[x] = (int)g[x].size() - 1;
    38 }
    39 
    40 int main() {
    41     scanf("%d", &n);
    42     for (int i = 1, x, y; i < n; ++i) {
    43         scanf("%d%d", &x, &y);
    44         Add(x, y); Add(y, x);
    45     }
    46     Dfs(1, 0);
    47     for (int i = 1; i <= n; ++i) {
    48         printf("%d
    ", hig[i] - res[i]);
    49     }
    50     
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    无线网路优化
    【设计模式】索引
    【c++算法】已序区间算法
    (转载)一个华为11年员工的国际惯例
    选择的结果
    明确价值体现
    只谈需求
    用block改写UIButton点击事件,block改写UIAlerView的代理
    UITableViewCell的三种加载方式
    如何从一个类的ViewController,如何获取一个UIView上的某种控件
  • 原文地址:https://www.cnblogs.com/Dance-Of-Faith/p/9322458.html
Copyright © 2011-2022 走看看