• 蓝桥杯模拟赛 青出于蓝而胜于蓝


    武当派一共有 nn 人,门派内 nn 人按照武功高低进行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn。现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟。

    我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 pp。也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝。

    请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超过了他自己。

    输入格式

    输入第一行两个整数 n, p(1 le n le 100000, 1 le p le n)n,p(1n100000,1pn)。

    接下来 n-1n1 行,每行输入两个整数 u, v(1 le u, v le n)u,v(1u,vn),表示 uu 和 vv 之间存在师徒关系。

    输出格式

    输出一行 nn 个整数,第 ii 个整数表示武功排行为 ii 的人的子弟有多少人超过了他。

    行末不要输出多余的空格。

    样例输入

    10 5
    5 3
    5 8
    3 4
    3 1
    2 1
    6 7
    8 7
    9 8
    8 10

    样例输出

    0 0 2 0 4 0 1 2 0 0

    dfs序列+树状数组
    利用dfs序列把树序列化,并可以用时间戳来维护一个非叶子节点的子树。对于一个区间 求这个区间内比某个值要小的值的个数,利用权值线段树的思想
    代码:
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    #include <queue>
    using namespace std;
    const int maxn=100010;
    int n,m;
    vector<int> edge[maxn];
    int in[maxn*2],out[maxn*2];
    int ret;
    int tree[maxn*2];
    int lowbit(int t)
    {
        return t&(-t);
    }
    void up(int x,int y)
    {
        for(int i=x;i<=n;i+=lowbit(i))
            tree[i]+=y;
    }
    int getsum(int x)
    {
        int ans=0;
        for(int i=x;i>0;i-=lowbit(i)) ans+=tree[i];
        return ans;
    }
    void init()
    {
        memset(tree,0,sizeof(tree));
        ret=0;
        for(int i=0;i<=n;i++) edge[i].clear();
    }
    void dfs(int u,int fa)
    {
        in[u]=++ret;
        int len=edge[u].size();
        for(int i=0;i<len;i++)
        {
            if(edge[u][i]!=fa)
            {
                dfs(edge[u][i],u);
            }
        }
        out[u]=ret;
    }
    int main()
    {
        scanf("%d %d",&n,&m);
        init();
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            edge[x].push_back(y);
            edge[y].push_back(x);
        }
        dfs(m,m);
        for(int i=1;i<=n;i++)
        {
            cout<<getsum(out[i])-getsum(in[i]);
            if(i!=n) cout<<" ";
            up(in[i],1);
        }
        cout<<endl;
        return 0;
    }
  • 相关阅读:
    两分钟彻底让你明白Android Activity生命周期(图文)!
    C++命名空间 namespace的作用和使用解析
    编译型语言、解释型语言、静态类型语言、动态类型语言概念与区别
    git 使用详解(8)-- tag打标签
    C#托管代码与C++非托管代码互相调用
    Qt属性表控件的使用 QtTreePropertyBrowser
    在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)
    (二十二)访问者模式详解(伪动态双分派)
    (二十一)状态模式详解(DOTA版)
    (二十)职责链模式详解(都市异能版)
  • 原文地址:https://www.cnblogs.com/z1141000271/p/8383688.html
Copyright © 2020-2023  润新知