Luogu3942 将军令

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/83410717

原题链接:https://www.luogu.org/problemnew/show/P3942

将军令

题目背景

pdf题面和大样例链接:http://pan.baidu.com/s/1cawM7c 密码:xgxv

 历史/落在/赢家/之手 
 至少/我们/拥有/传说 
 谁说/败者/无法/不朽 
 拳头/只能/让人/低头 
 念头/却能/让人/抬头 
 抬头/去看/去爱/去追 
 你心中的梦   
题目描述

又想起了四月。

如果不是省选,大家大概不会这么轻易地分道扬镳吧? 只见一个又一个昔日的队友离开了机房。

凭君莫话封侯事,一将功成万骨枯。

梦里,小 F 成了一个给将军送密信的信使。

现在,有两封关乎国家生死的密信需要送到前线大将军帐下,路途凶险,时间紧迫。小 F 不因为自己的祸福而避趋之,勇敢地承担了这个任务。

不过,小 F 实在是太粗心了,他一不小心把两封密信中的一封给弄掉了。

小 F 偷偷打开了剩下的那封密信。他 发现一副十分详细的地图,以及几句批文——原来 这是战场周围的情报地图。他仔细看后发现,在这张地图上标记了 n 个从 1 到 n 标号的 驿站,n − 1 条长度为 1 里的小道,每条小道双向连接两个不同的驿站,并且驿站之间可以 通过小道两两可达。

小 F 仔细辨认着上面的批注,突然明白了丢失的信的内容了。原来,每个驿站都可以驻 扎一个小队,每个小队可以控制距离不超过 k k 里的驿站。如果有驿站没被控制,就容易产 生危险——因此这种情况应该完全避免。而那封丢失的密信里,就装着朝廷数学重臣留下的 精妙的排布方案,也就是用了最少的小队来控制所有驿站。

小 F 知道,如果能计算出最优方案的话,也许他就能够将功赎过,免于死罪。他找到了 你,你能帮帮他吗? 当然,小 F 在等待你的支援的过程中,也许已经从图上观察出了一些可能会比较有用的 性质,他会通过一种特殊的方式告诉你。

输入输出格式
输入格式:

从标准输入中读入数据。

输入第 1 1 行一个正整数 n , k , t n,k,t ,代表驿站数,一支小队能够控制的最远距离,以及特殊性质所代表的编号。关于特殊性质请参照数据范围。

输入第 2 2 行至第 n n 行,每行两个正整数 u i , v i u_i ,v_i ,表示在 u i u_i v i v_i 间,有一条长度为 一里的小道。

输出格式:

输出到标准输出中。

输出一行,为最优方案下需要的小队数。

输入输出样例
输入样例#1:

4 1 0
1 2
1 3
1 4

输出样例#1:

1

输入样例#2:

6 1 0
1 2
1 3
1 4
4 5
4 6

输出样例#2:

2

说明
【样例 1 说明】

如图。由于一号节点到周围的点距离均是 1,因此可以控制所有驿站。

【样例 2 说明】

如图,和样例 1 类似。

子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解 决一部分测试数据。

关于 t t 的含义如下: t = 0 t = 0 :该测试点没有额外的特殊性质; t = 1 t = 1 :保证最多 8 8 个点的所连接的小道超过 1 1 条; t = 2 t = 2 :保证所有点到 1 1 号点的距离不超过 2 2

每个测试点的数据规模及特点如下表

题解

可以使用消防站的设立的思路,从维护爷爷变成维护 k k 级祖先,复杂度 O ( n k ) O(nk)

不过还有一种更优秀的 O ( n ) O(n) 做法,我们维护对于每个点向下离自己最远的没有覆盖的点的距离,如果该点有一支小队,距离为 k 1 -k-1 ,合并子树信息时,如果最小值+最大值<0,说明有小队可以覆盖这个点,该点的值为最小值+1,反之为最大值+1,当当前点值大于 k k 时,设立小队。

代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int head[M],nxt[M<<1],to[M<<1],dis[M],ans,cnt,n,k;
void add(int f,int t){nxt[++cnt]=head[f],head[f]=cnt,to[cnt]=t;}
void dfs(int f,int v)
{
    int mx=0,mn=M;
    for(int i=head[v];i;i=nxt[i])if(to[i]!=f)dfs(v,to[i]),mx=max(mx,dis[to[i]]+1),mn=min(mn,dis[to[i]]+1);
    dis[v]=(mx+mn<0?mn:mx);
    if(dis[v]>=k)dis[v]=-k-1,++ans;
}
void in(){scanf("%d%d%*d",&n,&k);for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),add(a,b),add(b,a);}
void ac(){dfs(0,1);if(dis[1]>=0)++ans;printf("%d",ans);}
int main(){in(),ac();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/83410717