Submission #1244722

#TimeUsernameProblemLanguageResultExecution timeMemory
1244722borisAngelovCat in a tree (BOI17_catinatree)C++20
100 / 100
315 ms37676 KiB
#include <bits/stdc++.h>

using namespace std;

const int maxn = 200005;
const int LOG = 18;
const int inf = 1e9 + 7;

int n, d;
vector<int> g[maxn];

int jump[maxn][LOG];
int depth[maxn];
vector<int> tour;

void dfs(int node, int par, int d)
{
    tour.push_back(node);
    depth[node] = d;
    jump[node][0] = par;

    for (auto to : g[node])
    {
        if (to != par)
        {
            dfs(to, node, d + 1);
        }
    }
}

void buildSparse()
{
    for (int log = 1; log < LOG; ++log)
    {
        for (int i = 1; i <= n; ++i)
        {
            jump[i][log] = jump[jump[i][log - 1]][log - 1];
        }
    }
}

int findLCA(int x, int y)
{
    if (depth[x] < depth[y]) swap(x, y);
    int diff = depth[x] - depth[y];

    for (int i = 0; i < LOG; ++i)
    {
        if ((diff & (1 << i)) != 0)
        {
            x = jump[x][i];
            diff -= (1 << i);
            if (diff == 0) break;
        }
    }

    if (x == y) return x;

    for (int i = LOG - 1; i >= 0; --i)
    {
        if (jump[x][i] != jump[y][i])
        {
            x = jump[x][i];
            y = jump[y][i];
        }
    }

    return jump[x][0];
}

int dist(int x, int y)
{
    int lca = findLCA(x, y);
    return depth[x] + depth[y] - 2 * depth[lca];
}

int sz[maxn];
int parent[maxn];
bool seen[maxn];

void dfsInit(int node, int par)
{
    sz[node] = 1;

    for (auto to : g[node])
    {
        if (to != par && seen[to] == false)
        {
            dfsInit(to, node);
            sz[node] += sz[to];
        }
    }
}

int findCentroid(int node, int par, int whole)
{
    for (auto to : g[node])
    {
        if (to != par && seen[to] == false && sz[to] > whole / 2)
        {
            return findCentroid(to, node, whole);
        }
    }

    return node;
}

int decompose(int node)
{
    dfsInit(node, -1);
    //cout << "decompose with " << node << " :: " << sz[node] << endl;
    
    int c = findCentroid(node, -1, sz[node]);
    seen[c] = true;
    //cout << "found " << c << endl;

    for (auto to : g[c])
    {
        if (seen[to] == false)
        {
            int newC = decompose(to);
            parent[newC] = c;
        }
    }

    return c;
}

int minDist[maxn];

void fastIO()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
}

int main()
{
    fastIO();

    cin >> n >> d;

    for (int i = 2; i <= n; ++i)
    {
        int par;
        cin >> par;
        ++par;
        g[i].push_back(par);
        g[par].push_back(i);
        //cout << "edge " << i << " " << par << endl;
    }

    dfs(1, 1, 0);
    buildSparse();
    sort(tour.begin(), tour.end(), [&](int x, int y)
    {
        return depth[x] > depth[y];
    });

    for (int i = 1; i <= n; ++i)
    {
        parent[i] = -1;
        minDist[i] = inf;
    }

    decompose(1);

    /*for (int i = 1; i <= n; ++i)
    {
        cout << i << " :: " << parent[i] << endl;
    }*/

    int ans = 0;

    for (auto node : tour)
    {
        int currentNode = node;
        int currMin = inf;
        
        while (currentNode != -1)
        {
            currMin = min(currMin, dist(node, currentNode) + minDist[currentNode]);
            currentNode = parent[currentNode];
        }

        //cout << "on " << node << " -> " << currMin << endl;

        if (currMin < d)
        {
            continue;
        }

        //cout << "mark " << node << endl;

        ++ans;
        
        currentNode = node;
        while (currentNode != -1)
        {
            minDist[currentNode] = min(minDist[currentNode], dist(node, currentNode));
            currentNode = parent[currentNode];
        }
    }

    cout << ans << endl;

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