zoukankan      html  css  js  c++  java
  • 洛谷 U138346 统治王国

    洛谷 U138346 统治王国

    洛谷传送门

    题目背景

    某日午后,SeawaySeawa**y一觉醒来,发现自己穿越到了蒟蒻王国,并当上了蒟蒻王国的国王......在反穿越失败后,SeawaySeawa**y接受了这个事实,并尝试着统治这个王国......

    题目描述

    蒟蒻王国一共有NN个城市,N-1N−1条可以双向通行的链接两个城市的道路,每条道路的长度相等。并且,蒟蒻王国的所有城市间两两可达。SeawaySeawa**y的王宫位于11号城市。为了统治蒟蒻王国,SeawaySeawa**y需要出宫巡视;并且,为了展现自己对底层人民的关怀,SeawaySeawa**y只关心自己到达了多少“偏远城市”,偏远城市的定义是:只有一条路与外界相连的城市。但是,贵为一国之王,SeawaySeawa**y的巡视路线要遵循王室的标准,在每座他停留的城市,他只能选择两种方式继续巡视:

    第一种:如果当前城市不是偏远城市,那么去往当前城市下辖的任意一个偏远城市。这里的下辖指:除了王宫方向之外的所有方向。

    第二种:如果当前城市是偏远城市,那么他可以向着王宫的方向巡视不超过KK个城市。

    特别地,因为11号城市是王宫所在,所以即便1号城市只有一条路与外界相连,它也不属于偏远城市。

    作为蒟蒻王国的总会计师,SeawaySeawa**y要你帮他规划出:他此次巡视最多能巡视多少偏远城市。

    由于答案可能较大,请输出答案对998244353998244353取模的结果。

    输入格式

    从文件kingdom.inkingdom.i**n中读入数据。

    第一行包括两个整数N,KN,K

    第二行包含N-1N−1个整数,第ii个整数f_if**i表示第i+1i+1号城市的上级城市。输入保证11号城市是所有城市的上级。

    输出格式

    输出到文件kingdom.outkingdom.out中。

    仅一行一个整数,表示可以巡视的最多偏远城市数对998244353998244353取模的结果。


    命题背景:

    没啥背景。

    题解:

    之前对这道题理解还是不深,再来重新说一遍。

    题意应该是很好概括的吧,不多说了。

    看到树上最优化看看树形DP行不行。

    行!

    统计啥呢?直接统计这个点能到达多少叶子节点,也就是直接设答案?不太行。为啥呢?因为没法转移,你不知道儿子能走到的叶子节点能不能走到你,因为有K步作为限制。

    那么我们设置dp[i]表示由多少叶子节点出发能够到达i。注意这跟上面的状态不一样!这是从上往下走的。

    这个的转移方程很好想。只需要统计一个数组low[i]表示离i最近的叶子节点深度即可。也很容易求出来。求出来这个又有什么用呢?

    就可以从根出发,找一条size和最大的路径。

    为了避免重复统计,我们把size更新完就清空。

    代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=1e6+10;
    const int INF=1e9;
    int n,k;
    int tot,head[maxn],nxt[maxn<<1],to[maxn<<1];
    int deep[maxn],size[maxn],low[maxn];
    bool v[maxn];
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    void dfs1(int x,int d)
    {
        deep[x]=d;
        low[x]=INF;
        if(!v[x])
            low[x]=d;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            dfs1(y,d+1);
            low[x]=min(low[x],low[y]);
        }
    }
    void dfs2(int x)
    {
        if(!v[x])
            size[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            dfs2(y);
            if(low[y]-deep[x]<=k)
            {
                size[x]+=size[y];
                size[y]=0;
            }
        }
    }
    int getsum(int x)
    {
        int ret=0;
        for(int i=head[x];i;i=nxt[i])
            ret=max(ret,getsum(to[i]));
        return ret+=size[x];
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=2;i<=n;i++)
        {
            int a;
            scanf("%d",&a);
            add(a,i);
            v[a]=1;
        }
        dfs1(1,0);
        dfs2(1);
        printf("%d",getsum(1));
        return 0;
    }
    
  • 相关阅读:
    JVM 综述
    看 Netty 在 Dubbo 中如何应用
    Netty 心跳服务之 IdleStateHandler 源码分析
    Netty 高性能之道
    Netty 解码器抽象父类 ByteToMessageDecoder 源码解析
    Netty 源码剖析之 unSafe.write 方法
    Netty 出站缓冲区 ChannelOutboundBuffer 源码解析(isWritable 属性的重要性)
    Netty 源码剖析之 unSafe.read 方法
    Netty 内存回收之 noCleaner 策略
    Netty 源码阅读的思考------耗时业务到底该如何处理
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13903820.html
Copyright © 2011-2022 走看看