Submission #1369567

#TimeUsernameProblemLanguageResultExecution timeMemory
1369567LOLOLOCat in a tree (BOI17_catinatree)C++17
100 / 100
258 ms59552 KiB
#include <bits/stdc++.h>
using namespace std;

const int INF = 1e9;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, D;
    cin >> N >> D;

    vector<vector<int>> adj(N);
    vector<int> depth(N, 0);

    for (int i = 1; i < N; i++) {
        int x;
        cin >> x;
        adj[x].push_back(i);
        adj[i].push_back(x);
        depth[i] = depth[x] + 1;
    }

    /*
        centroidInfo[u] chứa các cặp (c, dist(u, c)),
        với c là một centroid ancestor của u trong centroid decomposition.
    */
    vector<vector<pair<int, int>>> centroidInfo(N);

    vector<int> sub(N), parent(N);
    vector<char> removed(N, false);

    /*
        Xây centroid decomposition dạng iterative để tránh tràn stack
        khi cây là một đường thẳng dài.
    */
    vector<int> starts;
    starts.push_back(0);

    while (!starts.empty()) {
        int start = starts.back();
        starts.pop_back();

        if (removed[start]) continue;

        // Lấy toàn bộ component hiện tại
        vector<int> comp;
        vector<int> st;
        st.push_back(start);
        parent[start] = -1;

        while (!st.empty()) {
            int u = st.back();
            st.pop_back();
            comp.push_back(u);

            for (int v : adj[u]) {
                if (v == parent[u] || removed[v]) continue;
                parent[v] = u;
                st.push_back(v);
            }
        }

        // Tính size subtree trong component
        for (int i = (int)comp.size() - 1; i >= 0; i--) {
            int u = comp[i];
            sub[u] = 1;

            for (int v : adj[u]) {
                if (!removed[v] && parent[v] == u) {
                    sub[u] += sub[v];
                }
            }
        }

        int total = (int)comp.size();

        // Tìm centroid của component
        int centroid = comp[0];
        int bestBalance = total + 1;

        for (int u : comp) {
            int mx = total - sub[u];

            for (int v : adj[u]) {
                if (!removed[v] && parent[v] == u) {
                    mx = max(mx, sub[v]);
                }
            }

            if (mx < bestBalance) {
                bestBalance = mx;
                centroid = u;
            }
        }

        // Thêm thông tin khoảng cách từ mọi đỉnh trong component tới centroid
        vector<tuple<int, int, int>> st2;
        st2.push_back({centroid, -1, 0});

        while (!st2.empty()) {
            auto [u, p, dist] = st2.back();
            st2.pop_back();

            centroidInfo[u].push_back({centroid, dist});

            for (int v : adj[u]) {
                if (v == p || removed[v]) continue;
                st2.push_back({v, u, dist + 1});
            }
        }

        // Xóa centroid ra khỏi cây để chia component
        removed[centroid] = true;

        for (int v : adj[centroid]) {
            if (!removed[v]) {
                starts.push_back(v);
            }
        }
    }

    // Duyệt các đỉnh theo depth giảm dần
    vector<int> order(N);
    iota(order.begin(), order.end(), 0);

    sort(order.begin(), order.end(), [&](int a, int b) {
        if (depth[a] != depth[b]) return depth[a] > depth[b];
        return a < b;
    });

    /*
        best[c] = khoảng cách nhỏ nhất từ centroid c
                  tới một đỉnh đã được chọn.
    */
    vector<int> best(N, INF);

    long long answer = 0;

    for (int u : order) {
        int nearest = INF;

        // Query: tìm đỉnh đã chọn gần u nhất
        for (auto [c, distUC] : centroidInfo[u]) {
            nearest = min(nearest, best[c] + distUC);
        }

        // Nếu u cách mọi đỉnh đã chọn ít nhất D, chọn u
        if (nearest >= D) {
            answer++;

            // Update: thêm u vào tập đã chọn
            for (auto [c, distUC] : centroidInfo[u]) {
                best[c] = min(best[c], distUC);
            }
        }
    }

    cout << answer << '\n';

    return 0;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...