Blood Cousins - 树上启发式合并+倍增

题意: 在一个森林中,如果两个节点a和b向上的第p个祖先相同,就称他们为p代表亲。(跟日常生活中有所不同,p不一定是他们的最近公共祖先)。
给出一些询问,问v的p代表亲的数量。

看起来挺麻烦,但如果我们转化一下题意,就是找一个节点的有几个同深度的子节点。
所以只需要在输入时,把题目给我们的v,p,通过倍增转化成u,dep,这里的dep是相对于u的。
那就是一道裸的dsu on tree 板子了。

//
// Created by SANZONG on 2021/7/6.
//

#include "bits/stdc++.h"

using namespace std;
const int maxn = 6e5;
int head[maxn << 1];
int cnt;
struct node {
    
    
    int next, to;
} a[maxn << 1];
struct Query {
    
    
    int p, id;
};
vector<Query> query[maxn];
int dep[maxn];

void add(int u, int v) {
    
    
    a[++cnt].next = head[u];
    a[cnt].to = v;
    head[u] = cnt;
}

int son[maxn];
int siz[maxn];
int fath[maxn][25];

void dfsFir(int u, int fa, int deep) {
    
    
    dep[u] = deep;
    siz[u] = 1;
    fath[u][0] = fa;
    for (int i = 1; i <= 24; ++i) {
    
    
        fath[u][i] = fath[fath[u][i - 1]][i - 1];
    }
    for (int i = head[u]; i; i = a[i].next) {
    
    
        int v = a[i].to;
        if (v == fa) continue;
        dfsFir(v, u, deep + 1);
        siz[u] += siz[v];
        if (siz[v] > siz[son[u]]) {
    
    
            son[u] = v;
        }
    }
}

int flag;
int res[maxn];
int h[maxn];

void count(int u, int fa, int val) {
    
    
    h[dep[u]] += val;
    for (int i = head[u]; i; i = a[i].next) {
    
    
        int v = a[i].to;
        if (v == fa || v == flag) continue;
        count(v, u, val);
    }
}

void dfsSec(int u, int fa, int keep) {
    
    
    for (int i = head[u]; i; i = a[i].next) {
    
    
        int v = a[i].to;
        if (v == fa || v == son[u]) continue;
        dfsSec(v, u, 0);
    }
    if (son[u]) {
    
    
        dfsSec(son[u], u, 1);
        flag = son[u];
    }
    count(u, fa, 1);
    if (u != 0) {
    
    
        for (Query q : query[u]) {
    
    
            int id = q.id;
            int dis = q.p;
//            cout << id << ' ' << dis + dep[u] << ' ' << h[dis + dep[u]] << endl;
            res[id] = h[dis + dep[u]] - 1;
        }
    }
    flag = 0;
    if (!keep) {
    
    
        count(u, fa, -1);
    }
}

int get_fa(int x, int d) {
    
    
    int t = dep[x] - d;   //fa的dep
    for (int i = 20; i >= 0; --i) {
    
    
        if (dep[fath[x][i]] > t) x = fath[x][i];
    }
//    cout << x << ' ' << d << ' ' << fath[x][0] << endl;
    return fath[x][0];
}

int main() {
    
    
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n, q;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
    
    
        int u;
        cin >> u;
        add(i, u);
        add(u, i);
    }
    dfsFir(0, -1, 0);
    cin >> q;
    for (int i = 1; i <= q; ++i) {
    
    
        int v, p;
        cin >> v >> p;
        query[get_fa(v, p)].push_back(Query{
    
    p, i});
    }

    dfsSec(0, -1, 0);
    for (int i = 1; i <= q; ++i) {
    
    
        cout << res[i] << endl;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45509601/article/details/118609052