[贪心][Usaco2018 Jan]Cow at Large

BZOJ5189(点了没用,根本就没有题面)
友情一句话题意:给定一棵有根树,你开始在根节点,出口是每个叶子节点,可以在每个出口放一个守卫,每1个单位时间内,你和守卫都可以移动到相邻的一个点,如果某一时刻 守卫与你相遇了(在边上或点上均算),则你将被抓住。问为了保证抓住你,最少需要几个守卫。数据规模1e5

分析:
当然守卫是不可能往下走的,这一点和NOIP2012疫情控制有些相似
因为移动速度是相同的,时间是相等的,所以你和守卫总会在一条根到叶子节点的路径的中点处相遇,所以这个中点以下的点都可以用一个守卫控制
我们预处理每个点到离它最近的叶子节点的距离和它的dep,然后从根节点出发遇到的所有第一个mn[v]<=dep[v]的结点v的数量就是ans

至于wsm我要做这道题,因为下午要给三楼的巨佬们讲课,所以本蒟蒻要先整理一下

Code:

#include
#define INF 1e6
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=100005;
int vis[N<<1],head[N<<1],nxt[N<<1],tot=0;
int mn[N],dep[N],pt[N];
int n,m;
int ans=0;
inline void add(int x,int y) {vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs(int v){
	pt[v]=1;mn[v]=INF;
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(pt[y]) continue;
		dep[y]=dep[v]+1;
		dfs(y);
		mn[v]=min(mn[v],mn[y]+1);
	}
	if(mn[v]==INF) mn[v]=0;
}
int pt1[N];
void calc(int v){
	pt1[v]=1;
	if(mn[v]<=dep[v]) {++ans;return;}
	for(int i=head[v];i;i=nxt[i]){
		if(pt1[vis[i]]) continue;
		calc(vis[i]);
	}
}
int main(){
	n=read(),m=read();
	for(int x,y,i=1;i<n;i++){
		x=read(),y=read();
		add(x,y);add(y,x);
	}
	dfs(m);
	calc(m);
	cout<<ans<<"\n";
	return 0;
}

你可能感兴趣的:([贪心][Usaco2018 Jan]Cow at Large)