Loading

Codeforces Round #130 (Div. 2) E Blood Cousins

Blood Cousins

树上启发式合并 || \(dfs\) 序 + 二分

树上启发式合并就直接根据深度来合并起来就好了,答案就是问的那个点的 \(k\) 级祖先下,深度与问的那个点的儿子数量 - 1

对深度进行一个启发式合并就好了

好像还可以长链剖分?

注意该题是森林

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <array>
using namespace std;
const int maxn = 1e5 + 10;
#define pii pair<int, int>
int dep[maxn], L[maxn], rnk[maxn], R[maxn];
int hson[maxn], siz[maxn], fa[maxn];
int tp = 0, n, m, ans[maxn];
int cnt[maxn];
vector<int>gra[maxn];
vector<pii>qa[maxn], qb[maxn];
int st[maxn], stp = 0;

void dfs1(int now, int d)
{
    dep[now] = d;
    L[now] = ++tp;
    rnk[tp] = now;
    siz[now] = 1;
    hson[now] = -1;
    st[++stp] = now;
    for(auto [x, y] : qa[now])
    {
        if(stp - x > 0)
            qb[st[stp - x]].push_back({x, y});
    }
    for(int nex : gra[now])
    {
        if(nex == fa[now]) continue;
        dfs1(nex, d + 1);
        siz[now] += siz[nex];
        if(hson[now] == -1 || siz[nex] > siz[hson[now]])
            hson[now] = nex;
    }
    st[stp--] = 0;
    R[now] = tp;
}

inline void add(int now)
{
    cnt[dep[now]]++;
}

inline void del(int now)
{
    cnt[dep[now]]--;
}

void dfs2(int now, bool keep)
{
    for(int nex : gra[now])
        if(nex != fa[now] && nex != hson[now]) dfs2(nex, false);
    if(hson[now] != -1)
        dfs2(hson[now], true);
    for(int nex : gra[now])
    {
        if(nex != fa[now] && nex != hson[now])
        {
            for(int i=L[nex]; i<=R[nex]; i++)
            {
                add(rnk[i]);
            }
        }
    }
    add(now);
    for(auto [x, y] : qb[now])
    {
        if(x + dep[now] <= n)
            ans[y] = max(cnt[x + dep[now]] - 1, 0);
    }
    if(!keep)
    {
        for(int i=L[now]; i<=R[now]; i++)
            del(rnk[i]);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for(int i=1; i<=n; i++)
    {
        cin >> fa[i];
        if(fa[i])
            gra[fa[i]].push_back(i);
    }
    cin >> m;
    for(int i=0; i<m; i++)
    {
        int a, b;
        cin >> a >> b;
        qa[a].push_back({b, i});
    }
    for(int i=1; i<=n; i++)
    {
        if(fa[i] == 0)
        {
            dfs1(i, 1);
            dfs2(i, false);
        }
    }
    for(int i=0; i<m; i++)
        cout << ans[i] << " ";
    cout << "\n";
    return 0;
}

\(dfs\) 序 + 二分

考虑其 \(dfs\) 序,按照深度为第一关键字,\(dfs\) 序为第二关键字,排序之后,找到对应深度的位置,通过 \(dfs\) 序,二分判断该深度子节点的数量

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <array>
using namespace std;
vector<int>dep, fa, L, R, ans, st;
int tp = 0;
vector<vector<int> >gra, de;
vector<vector<array<int, 2> > >qs;

void dfs(int now, int d)
{
    dep[now] = d;
    L[now] = ++tp;
    st.push_back(now);
    for(auto [x, i] : qs[now])
        if((int)st.size() - x - 1 >= 0)
            qs[st[(int)st.size() - 1 - x]].push_back({dep[now], i});
    qs[now].clear();
    de[dep[now]].push_back(tp);
    for(int nex : gra[now])
    {
        if(nex == fa[now]) continue;
        dfs(nex, d + 1);
    }
    R[now] = tp;
    st.pop_back();
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin >> n;
    L.resize(n + 1);
    R.resize(n + 1);
    dep.resize(n + 1);
    fa.resize(n + 1);
    gra.resize(n + 1);
    de.resize(n + 1);
    for(int i=1; i<=n; i++)
    {
        cin >> fa[i];
        gra[fa[i]].push_back(i);
    }
    int m;
    cin >> m;
    qs.resize(n + 1);
    ans.resize(m);
    for(int i=0; i<m; i++)
    {
        int a, b;
        cin >> a >> b;
        qs[a].push_back({b, i});
    }
    for(int i=1; i<=n; i++) if(fa[i] == 0) dfs(i, 0);
    for(int i=0; i<n; i++)
        sort(de[i].begin(), de[i].end());
    for(int i=1; i<=n; i++)
    {
        for(auto [d, id] : qs[i])
        {
            ans[id] = upper_bound(de[d].begin(), de[d].end(), R[i]) - lower_bound(de[d].begin(), de[d].end(), L[i]) - 1;
        }
    }
    for(int i=0; i<m; i++)
    {
        if(i) cout << " ";
        cout << ans[i];
    }
    cout << endl;
    return 0;
}
posted @ 2022-09-17 23:25  dgsvygd  阅读(48)  评论(0)    收藏  举报