• 2020牛客多校第四场A-Ancient Distance


    https://ac.nowcoder.com/acm/contest/5669/A

    题意

    给一个有根树,在树上选择 k 个关键点(根必须选)

    最小化点到最近关键祖先距离的最大值

    求出 k 分别为 1,2,…,n 时答案的和

    题解

    首先考虑暴力,当k固定,可以二分答案x,每次选择深度最深的点,将它第x个祖先的子树删除,直到将整棵树删完,比较删除点的数量和k的大小关系改变二分范围

    如何计算关键点的数量即为关键。可以对整棵树维护一个dfs序,用线段树操作子树,每次找到线段树中最深的点p,从p向上找dis个祖先,把这个节点的子树染色。

    反过来枚举dis,计算这个dis关键点数量,可以把二分答案的复杂度去掉

    复杂度(O(Nlog^2N))

    代码

    #include <bits/stdc++.h>
    #define lson (o << 1)
    #define rson (o << 1 | 1)
    using namespace std;
    typedef long long ll;
    
    const int N = 2e5 + 5;
    vector<int> G[N];
    int in[N], out[N];
    int fa[N][20];
    int point[N];
    int dep[N];
    int cnt = 0;
    void dfs(int u, int f) {
        in[u] = ++cnt;
        point[cnt] = u;
        fa[u][0] = f;
        dep[u] = dep[f] + 1;
        for (int v : G[u]) {
            if (v == f) continue;
            dfs(v, u);
        }
        out[u] = cnt;
    }
    struct node {
        int mx, cov, depst;
    } tree[N << 2];
    void pushup(int o) {
        tree[o].mx = 0;
        if (!tree[lson].cov && tree[lson].mx > tree[o].mx) {
            tree[o].mx = tree[lson].mx;
            tree[o].depst = tree[lson].depst;
        }
        if (!tree[rson].cov && tree[rson].mx > tree[o].mx) {
            tree[o].mx = tree[rson].mx;
            tree[o].depst = tree[rson].depst;
        }
    }
    void build(int o, int l, int r) {
        if (l == r) {
            tree[o].mx = dep[point[l]]; tree[o].depst = point[l]; tree[o].cov = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(lson, l, mid); build(rson, mid + 1, r);
        pushup(o);
    }
    void update(int o, int l, int r, int ql, int qr, int v) {
        if (ql <= l && r <= qr) {
            tree[o].cov = v;
            return;
        }
        int mid = (l + r) >> 1;
        if (ql <= mid) update(lson, l, mid, ql, qr, v);
        if (qr > mid) update(rson, mid + 1, r, ql, qr, v);
        pushup(o);
    }
    
    void init(int n) {
        cnt = 0;
        dep[0] = -1;
        dfs(1, 0);
        build(1, 1, n);
        for (int i = 1; i <= 19; i++) {
            for (int u = 1; u <= n; u++) {
                fa[u][i] = fa[fa[u][i - 1]][i - 1];
            }
        }
    }
    int kfa(int u, int k) {
        for (int i = 19; i >= 0; i--) {
            if (k & (1 << i)) u = fa[u][i];
        }
        return u;
    }
    int ans[N];
    int main() {
        int n; 
        while (~scanf("%d", &n)) {
            for (int i = 1; i <= n; i++) G[i].clear(), ans[i] = n - 1;
            for (int i = 2; i <= n; i++) {
                int x; scanf("%d", &x);
                G[i].push_back(x);
                G[x].push_back(i);
            }
            init(n);
            ll res = 0;
            for (int dis = 0; dis < n; dis++) {
                int k = 0;
                vector<int> tmp; tmp.clear();
                while (1) {
                    k++;
                    if (tree[1].mx <= dis) break;
                    int u = tree[1].depst;
                    u = kfa(u, dis);
                    tmp.push_back(u);
                    update(1, 1, n, in[u], out[u], 1);
                }
                for (int u : tmp) update(1, 1, n, in[u], out[u], 0);
                ans[k] = min(ans[k], dis);
            }
            for (int i = 2; i <= n; i++) ans[i] = min(ans[i], ans[i - 1]), res += ans[i];
            res += ans[1];
            printf("%lld
    ", res);
        }
        return 0;
    }
    
  • 相关阅读:
    thinkphp empty标签
    thinkphp present标签
    if标签
    thinkphp 范围标签
    thinkphp 比较标签
    thinkphp switch标签
    thinkphp for标签
    thinkphp foreach标签
    QueryList 来做采集
    thinkphp volist标签
  • 原文地址:https://www.cnblogs.com/artoriax/p/13594549.html
Copyright © 2020-2023  润新知