zoukankan      html  css  js  c++  java
  • [CF208E] Blood Cousins

    [CF208E] Blood Cousins - dsu on tree, LCA

    Description

    给你一片森林,每次询问一个点与多少个点拥有共同的 K 级祖先。

    Solution

    dsu on tree

    首先,求出一个点的 k 级祖先,并且把询问挂在他身上,问的就是这个点 p 子树内有多少个深度为 d 的点

    在 dfs 过程中,对每个点,递归处理各个孩子,同时保留其重孩子的贡献,再加上轻孩子的贡献,得到自身的贡献

    总结一下我们需要支持哪些事情:求 k 级祖先(倍增处理),将询问挂在祖先上,树上启发式合并处理所有询问

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    const int N = 1e5 + 5;
    
    ///////////////////////////////////////////////////
    
    vector<int> g[N];
    int n, wson[N], dep[N], siz[N], fa[N][20], ans[N];
    
    ///////////////////////////////////////////////////
    
    vector<pair<int, int>> question[N];
    
    ///////////////////////////////////////////////////
    
    int bucket[N];
    vector<int> record;
    
    void add(int p)
    {
        bucket[p]++;
        record.push_back(p);
    }
    
    void dec(int p)
    {
        bucket[p]--;
    }
    
    void clr()
    {
        for (auto i : record)
            dec(i);
        record.clear();
    }
    
    //////////////////////////////////////////////////
    
    int get_kth_father(int p, int k)
    {
        for (int i = 19; i >= 0; i--)
            if ((k >> i) & 1)
                p = fa[p][i];
        return p;
    }
    
    void make_question(int p, int k, int id)
    {
        int par = get_kth_father(p, k);
        if (par)
        {
            question[par].push_back(make_pair(dep[p], id));
        }
    }
    
    void dfs_pre(int p)
    {
        siz[p] = 1;
        for (int q : g[p])
        {
            dep[q] = dep[p] + 1;
            fa[q][0] = p;
            for (int j = 1; j < 20; j++)
                fa[q][j] = fa[fa[q][j - 1]][j - 1];
            dfs_pre(q);
            siz[p] += siz[q];
            if (siz[wson[p]] < siz[q])
                wson[p] = q;
        }
    }
    
    void dfs_add(int p)
    {
        add(dep[p]);
        for (int q : g[p])
            dfs_add(q);
    }
    
    void dfs(int p)
    {
        for (int q : g[p])
        {
            if (q == wson[p])
                continue;
            dfs(q);
            clr();
        }
        if (wson[p])
        {
            dfs(wson[p]);
        }
        for (int q : g[p])
        {
            if (q == wson[p])
                continue;
            dfs_add(q);
        }
        add(dep[p]);
    
        // cout << "p=" << p << endl;
        // for (int i = 0; i <= 10; i++)
        //     cout << bucket[i] << " ";
        // cout << endl;
        for (auto [depth, id] : question[p])
        {
            // cout << " question: " << depth << " " << id << endl;
            ans[id] = bucket[depth] - 1;
        }
    }
    
    ///////////////////////////////////////////////////
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            int r;
            cin >> r;
            g[r].push_back(i);
        }
    
        dfs_pre(0);
    
        int m;
        cin >> m;
        for (int i = 1; i <= m; i++)
        {
            int v, k;
            cin >> v >> k;
            make_question(v, k, i);
        }
    
        dfs(0);
    
        for (int i = 1; i <= m; i++)
            cout << ans[i] << " ";
    }
    
  • 相关阅读:
    使用一系列命令生成字母数字符号组合
    linux分析apache日志获取最多访问的前10个IP
    shell脚本输出九九乘法表
    shell脚本输出空心等腰三角形
    awk与sed命令面试题整理
    linux分析apache日志获取最多访问的前10个IP
    iOS开发-由浅至深学习block
    PM常用软件&工作平台
    iOS开发之—— 各种加密的使用(MD5,base64,DES,AES,RSA,DSA)
    MVVM With ReactiveCocoa
  • 原文地址:https://www.cnblogs.com/mollnn/p/14348852.html
Copyright © 2011-2022 走看看