洛谷 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;
}