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;
    }
    
  • 相关阅读:
    实现websocket中遇到的恶心问题。
    移动js框架使用报告
    超级难用的wireshark。
    三国演义LBS 20110406 本次清明节解决问题列表。
    【原创意】一个市值估算超亿的创意——愤怒的小猪(谢绝抄袭和冒名顶替)
    一个小游戏 让你感受“如何等待成功”!
    js 游戏引擎 + canvas 入门
    javascript 中的反射
    使用HTML5进行地理位置定位。误差在+500m
    【原创意】新浪微博都感到巨大鸭梨的全新创意 —— 二维码社区"神码"
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13903820.html
Copyright © 2011-2022 走看看