zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第四场) A Ancient Distance

    题解:这里主要讲一下官方题解的调和级数是怎么来的,因为当我们确定了一个最大 (Ancient Distance = x) 时,我们可以最多只用 (frac{n}{x}) 个关键的就可以让这棵树的 (Ancient Distance = x) ,所以我们用 (ans[i]) 表示当关键点个数为 (i) 时,(Ancient Distance) 的最小值, 然后从 (n - 1)(1) 枚举 (x) ,每次只要找不大于 (frac{n}{x}) 个点就可以确定当 (Ancient Distance = x) 时所需要的最小关键点,所以我们不考虑寻找深度的最小的点时的复杂度为 (sum_{i = 1}^{n}frac{n}{i} = nlog n) ,由于我们时反向遍历的,所以最后的 (ans[i]) 一定会是最小值,关于找最小点可以线段树维护 (dfs) 序,每次查询的复杂度为 (log n),所以总的复杂度为 (nlog n log n)

    第一份是官方题解的做法:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    #define lc (rt << 1)
    #define rc ((rt << 1) | 1)
    const int maxn = 2e5 + 50;
    const LL mod = 1e9 + 7;
    double eps = 1e-6;
     
    int n;
    struct Edge
    {
        int to, next;
    } edge[maxn * 2];
    
    int k, head[maxn];
    
    void add(int a, int b){
        edge[k].to = b;
        edge[k].next = head[a];
        head[a] = k++;
    }
    
    int dfn[maxn], dep[maxn], ln[maxn], rn[maxn], tot, fa[maxn][30], nodeid[maxn];
    void dfs(int u, int pre, int d){
        fa[u][0] = pre;
        ln[u] = ++tot;
        nodeid[tot] = u; 
        dep[tot] = d;
        for(int i = head[u]; i != -1; i = edge[i].next){
            int to = edge[i].to;
            if(to == pre) continue;
            dfs(to, u, d + 1);
        }
        rn[u] = tot;
    }
    
    void init(){
        dfs(1, -1, 0);
        for(int j = 0; (1 << (j + 1)) < n; j++){
            for(int i = 1; i <= n; i++){
                if(fa[i][j] < 0) fa[i][j + 1] = -1;
                else fa[i][j + 1] = fa[fa[i][j]][j]; 
            }
        }
    }
    int LCA(int u, int len){ // 倍增找向上走 len 步的节点
        len = min(len, dep[ln[u]]);
        for(int i = 0; (1 << i) <= len; i++){
            if(len & (1 << i)) u = fa[u][i];
        }
        return u;
    }
    
    int getMax(int u, int v){
        if(dep[u] >= dep[v]) return u;
        else return v;
    }
    int Lazy[maxn << 2];
    int tree[maxn << 2];
    void PushUp(int rt){
        tree[rt] = 0;
        if(!Lazy[lc]) tree[rt] = getMax(tree[rt], tree[lc]);
        if(!Lazy[rc]) tree[rt] = getMax(tree[rt], tree[rc]);
    }
    
    void Build(int le, int ri, int rt){
        if(le == ri){
            tree[rt] = le;
            return ;
        }
        int mid = (le + ri) >> 1;
        Build(le, mid, lc);
        Build(mid + 1, ri, rc);
        PushUp(rt);
    }
    
    void Update(int le, int ri, int L, int R, int val, int rt){
        if(L <= le && ri <= R){
            Lazy[rt] = val;
            return ;
        }
        int mid = (le + ri) >> 1;
        if(L <= mid) Update(le, mid, L, R, val, lc);
        if(R > mid) Update(mid + 1, ri, L, R, val, rc);
        PushUp(rt);
    }
    
    vector<int> vec;
    int ans[maxn];
    int main()
    {
        while(~scanf("%d", &n)){
            k = tot = 0;
            for(int i = 1; i <= n; i++) head[i] = -1;
            for(int i = 1; i < n; i++){
                int x;
                scanf("%d", &x);
                add(x, i + 1);
                add(i + 1, x);
            }
            init();
            for(int i = 0; i <= n; i++){
                ans[i] = n - 1;
            }
            Build(1, n, 1);
            for(int i = n - 1; i >= 0; i--){
                int cost = 1;
                while(1){
                    int u = tree[1];
                    if(dep[u] <= i) break;
                    u = LCA(nodeid[u], i);
                    vec.push_back(u);
                    cost++;
                    Update(1, n, ln[u], rn[u], 1, 1);
                }
                int len = vec.size();
                for(int u = 0; u < len; u++) Update(1, n, ln[vec[u]], rn[vec[u]], 0, 1);
                vec.clear();
                ans[cost] = i;
            }
            LL res = ans[1];
            for(int i = 2; i <= n; i++){
                ans[i] = min(ans[i - 1], ans[i]);
                res += ans[i];
            }
            printf("%lld
    ", res);
        }
        return 0;
    }
    
  • 相关阅读:
    修改Matlab的背景颜色
    lane车道连接规则
    用汇编语言输出Hello World!
    运用ISAPI_Rewrite将asp静态化应注意路径
    广州,佛山>黄岐生活资讯网生活信息发布
    最近使用网络电话,还比较便宜
    小心中中国移动“短号集群网”的招
    正规表达式的一些知识
    ubuntu 8.04下安装和使用systemtap
    应用程序框架设计之二:分层和层间数据传递(上)
  • 原文地址:https://www.cnblogs.com/PCCCCC/p/13395897.html
Copyright © 2011-2022 走看看