BZOJ5189(点了没用,根本就没有题面)
友情一句话题意:给定一棵有根树,你开始在根节点,出口是每个叶子节点,可以在每个出口放一个守卫,每1个单位时间内,你和守卫都可以移动到相邻的一个点,如果某一时刻 守卫与你相遇了(在边上或点上均算),则你将被抓住。问为了保证抓住你,最少需要几个守卫。数据规模1e5
分析:
当然守卫是不可能往下走的,这一点和NOIP2012疫情控制有些相似
因为移动速度是相同的,时间是相等的,所以你和守卫总会在一条根到叶子节点的路径的中点处相遇,所以这个中点以下的点都可以用一个守卫控制
我们预处理每个点到离它最近的叶子节点的距离和它的dep,然后从根节点出发遇到的所有第一个mn[v]<=dep[v]的结点v的数量就是ans
至于wsm我要做这道题,因为下午要给三楼的巨佬们讲课,所以本蒟蒻要先整理一下
Code:
#include<bits/stdc++.h>
#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;
}