洛谷 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;
}
原文地址:https://www.cnblogs.com/fusiwei/p/13903820.html