zoukankan      html  css  js  c++  java
  • D

    You are given a tree that represents a hierarchy in a company, where the parent of node u is their direct manager.

    Each employee is assigned a project, and multiple employees can be assigned to the same project. When it is time for the presentation of the ith project, all employees u that are assigned that project and their direct and indirect managers must attend the presentation (u and their manager and their manager's manager and so on until the CEO).

    Find for each project the number of people attending its presentation.


    Input

    The first line of input is n and m (1 ≤ m ≤ n ≤ 106), the number of employees and the number of projects, respectively.

    The second line of input contains n integers ai (1 ≤ ai ≤ m), where ai is the project assigned to the ith employee. It is guaranteed that each project has at least one employee assigned to it.

    The third line of input contains n integers pi (0 ≤ pi ≤ n), where pi is the direct manager of the ith employee. If pi = 0, then the ith employee is the CEO and does not have a manager. It is guaranteed that there is only one CEO, and this CEO is a direct or indirect manager of all other employees.

    Output

    Output m integers, where the ith integer is the number of people attending the presentation of the ith project.

    Example
    Input
    6 4
    1 2 4 3 2 4
    0 1 1 3 3 2
    
    Output
    1 4 3 4 
    题解:首先根据题意建树,每个节点有对应的任务(1~m),如果一个人处理i任务,那么他所有的祖先都得参与到当中,对于每一个任务,求参与到其中的人的数量。
    首先DFS序跑图,得到每个节点的入时间序,时间序对应的原节点,深度,走2^0步得到的节点。
    然后对于每一个任务:假设其中有x个人执行这个任务,我们首先将其按DFS序从小到大排序,然后有对应公式:sum+=dep[i]-dep[LCA(i-1,i)]。
    那么就该想如何实现这个过程了,下面是用的vector存储:
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1000100;
    int w[maxn],x,root,cnt;
    int Start[maxn],End[maxn],dep[maxn],par[24][maxn],Rev[maxn];
    vector<int>G[maxn],vv[maxn],ans;
    void DFS(int u,int pre,int d)
    {
        par[0][u]=pre;//u向上走2^0走到pre节点
        dep[u]=d;//u的深度
        Start[u]=++cnt;//DFS序对应值
        Rev[cnt]=u;//将其反过来转换为原来的节点
        for(int i=0;i<G[u].size();i++){
            DFS(G[u][i],u,d+1);
        }
        End[u]=cnt;
    }
    int LCA(int u,int v)
    {
        if(dep[u]>dep[v])swap(u,v);
        for(int k=0;k<20;k++){//让u和v走到同一深度
            if((dep[v]-dep[u])>>k&1){//这里简单理解下就是将u和v的距离用二进制表示,每一位1将其变为0
                v=par[k][v];
            }
        }
        if(u==v)return u;
        for(int k=19;k>=0;k--){
            if(par[k][u]!=par[k][v]){
                u=par[k][u];
                v=par[k][v];
            }
        }
        return par[0][u];
    }
    int main()
    {
        ios::sync_with_stdio(0);
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)cin>>w[i];
        for(int i=1;i<=n;i++){
            cin>>x;
            if(x!=0){
                G[x].push_back(i);
            }
            else
                root=i;
        }
        DFS(root,-1,1);
        for(int k=0;k<20;k++){//预处理par数组
            for(int v=1;v<=n;v++){
                if(par[k][v]==-1)par[k+1][v]=-1;
                else par[k+1][v]=par[k][par[k][v]];
            }
        }
        for(int i=1;i<=n;i++){
            vv[w[i]].push_back(Start[i]);
        }
        for(int i=1;i<=m;i++){
            sort(vv[i].begin(),vv[i].end());//按照DFS序递增排序,是为了不重复答案
            int sum=0;
            for(int j=0;j<vv[i].size();j++){
                if(j==0)sum+=dep[Rev[vv[i][j]]];
                else sum+=dep[Rev[vv[i][j]]]-dep[LCA(Rev[vv[i][j-1]],Rev[vv[i][j]])];
            }
            ans.push_back(sum);
        }
        for(int i=0;i<ans.size();i++)cout<<ans[i]<<" ";
        cout<<endl;
        return 0;
    }
  • 相关阅读:
    禁止ios默认拉动弹性行为
    javascript 网页图标音乐切换
    js常用 禁止F5 和右键
    弹窗插件
    手机时间选择插件 Jquery
    Jquery获取背景图片src路径
    Arduino 数字函数总结
    Arduino 开关控制小灯持续亮之具体思路
    C语言流控制命令的总结
    C++Primer 第四章 表达式
  • 原文地址:https://www.cnblogs.com/cherish-lin/p/11104797.html
Copyright © 2011-2022 走看看