zoukankan      html  css  js  c++  java
  • 1773:消息传递

    1773:消息传递

    时间限制: 1000 ms 内存限制: 262144 KB

    【题目描述】
    H国的社会等级森严,除了国王之外,每个人均有且只有一个直接上级,当然国王没有上级。如果A是B的上级,B是C的上级,那么A就是C的上级。绝对不会出现这样的关系:A是B的上级,B也是A的上级。

    最开始的时刻是0,你要做的就是用1单位的时间把一个消息告诉某一个人,让他们自行散布消息。在任意一个时间单位中,任何一个已经接到消息的人,都可以把消息告诉他的一个直接上级或者直接下属。

    现在,你想知道:

    ①到底需要多长时间,消息才能传遍整个H国的所有人?

    ②要使消息在传递过程中消耗的时间最短,可供选择的人有哪些?

    【输入】
    第一行为一个整数N,表示H国人的总数,假如人按照1到n编上了号码,国王的编号是1。

    第二行到第N行(共N−1行),每一行一个整数,第i行的整数表示编号为i的人直接上级的编号。

    【输出】
    输出共计两行:

    第一行为一个整数,表示最后一个人接到消息的最早时间。

    第二行有若干个数,表示可供选择人的编号,按照编号从小到大的顺序输出,中间用一个空格隔开。

    【输入样例】
    4
    1
    1
    1
    【输出样例】
    4
    1 2 3 4

    【输入样例2】

    8
    1
    1
    3
    4
    4
    4
    3
    【输出样例2】

    5
    3 4 5 6 7
    【数据规模与约定】

    对于20%的数据,N≤3000。

    对于50%的数据,N≤20000。

    对于100%的数据,N≤200000。

     【题解】

    实际上是一道水题。

    可以很方便的求出以u为根传递完它的子树的代价f[u]。

    考虑如何求出传完它父亲及其上方点的代价。

    使用换根dp。令g[u]表示去掉u及其子树并以u的父亲为根的全部代价。

    将所有儿子的f与自己的g排序后即可求出所有儿子的g。

    每个点的答案就很好计算了。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+5;
    int f[N],g[N],n,last[N],size,pre[N],sub[N],ans[N],ans1=999999999,daan[N],ans2;
    struct pigu
    {
        int dao,ne;
    }a[N];
    pair <int,int> b[N];
    inline void lingjiebiao(int x,int y)
    {
        a[++size].dao=y;
        a[size].ne=last[x];
        last[x]=size;
    }
    inline void dfs1(int now)
    {
        for(int i=last[now];i;i=a[i].ne)
            dfs1(a[i].dao);
        int cnt=0;
        for(int i=last[now];i;i=a[i].ne)
            b[++cnt]=make_pair(f[a[i].dao],a[i].dao);
        sort(b+1,b+cnt+1);
        for(int i=1;i<=cnt;i++)
            f[now]=max(f[now],b[i].first+cnt-i+1);
    }
    inline void dfs2(int now)
    {
        int cnt=0;
        for(int i=last[now];i;i=a[i].ne)
        {
            b[++cnt]=make_pair(f[a[i].dao],a[i].dao);
        }
        if(now!=1) b[++cnt]=make_pair(g[now],-1);
        if(cnt==1&&now==1) g[now]=1; 
        sort(b+1,b+cnt+1);
        for(int i=1;i<=cnt;i++) ans[now]=max(b[i].first+cnt-i+1,ans[now]);pre[0]=sub[cnt+1]=-1;
        for(int i=1;i<=cnt;i++) pre[i]=max(pre[i-1],b[i].first+cnt-i);
        for(int i=cnt;i>=2;i--) sub[i]=max(sub[i+1],b[i].first+cnt-i+1);
        for(int i=1;i<=cnt;i++)
        {
            if(b[i].second!=-1)
                g[b[i].second]=max(pre[i-1],sub[i+1]);
        }
        for(int i=last[now];i;i=a[i].ne) dfs2(a[i].dao);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=2,x;i<=n;i++)
        {
            scanf("%d",&x);
            lingjiebiao(x,i);
        }
        dfs1(1);
        dfs2(1);
        for(int i=1;i<=n;i++) 
            if(ans1>ans[i]) ans1=ans[i],daan[ans2=1]=i;
            else if(ans1==ans[i]) daan[++ans2]=i;
        cout<<ans1+1<<"
    ";
        for(int i=1;i<=ans2;i++) cout<<daan[i]<<" ";
        return 0;
    }
    View Code
  • 相关阅读:
    Oracle数据库相关问题
    常用Oracle数据库查询SQL
    VS2019添加引用错误:COM组件调用返回错误HRESULT E_FAIL
    C#.NET重点知识点汇总(三)
    C#.NET重点知识点汇总(二)
    C#.NET重点知识点汇总(一)
    ajax的19道经典面试题
    C#设计模式——抽象工厂模式
    C#设计模式——工厂方法模式
    C#设计模式——简单工厂模式
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12210779.html
Copyright © 2011-2022 走看看