题目描述
样例
input:
7 2
1 2
2 5
5 7
5 6
3 6
3 4
output:
1
题目大意
土拨鼠和
O
r
a
n
g
e
Orange
Orange同住在一棵树上。现在,土拨鼠去看望
O
r
a
n
g
e
Orange
Orange,他从1号结点出发,
O
r
a
n
g
e
Orange
Orange住在
n
n
n号结点。土拨鼠速度为
1
m
/
s
1m/s
1m/s,
t
t
t秒之后,
O
r
a
n
g
e
Orange
Orange发现自己发烧了,为了传染给土拨鼠,他以
2
m
/
s
2m/s
2m/s的速度追赶以
1
m
/
s
1m/s
1m/s速度逃跑的土拨鼠。
现在给定
n
,
t
n,t
n,t和树,要求土拨鼠从走向
O
r
a
n
g
e
t
Orange\,t
Oranget秒之后,他有多少时间可以存活。
分析
第一步肯定是找到土拨鼠
t
t
t秒之后的位置,这个很简单,求个深度和每个节点的父节点然后从
n
n
n开始向上跳即可。
接下来就是比较麻烦的求最长的那条路径。
我们第一想到的就是以现在土拨鼠的位置为根,除了
n
n
n那条链以外的链求最长的即可,你当然不会迎着
O
r
a
n
g
e
Orange
Orange走过去。但是很快就发现十分的不对。
不如我们看下面这种情况:
如果土拨鼠当前的位置在2,那么显然依照上面的策略,土拨鼠会在1号结点等死。但是还有个更优的策略就是向着
O
r
a
n
g
e
Orange
Orange走一步,然后拐到
4567
4567
4567那条链上可以存活更久。
那么这个应该怎么搞呢??
我们不妨把
O
r
a
n
g
e
Orange
Orange和土拨鼠到达每个节点的时间都标出来:
蓝色是土拨鼠,橙色是
O
r
a
n
g
e
Orange
Orange。
相应地,土拨鼠肯定是不能到达橙色小于等于蓝色的点的因为这样,
O
r
a
n
g
e
Orange
Orange就可以直接抓住他了。因此对于每条链,一旦找到一个不合法的点,那么这个点的父节点就是土拨鼠向这条链能走的最远的路,
a
n
s
ans
ans只要取这个点
O
r
a
n
g
e
Orange
Orange所需要的时间就可以了。
那么如果整条链都是合法的,显然,取叶节点就可以了。
所以,3个
d
f
s
dfs
dfs爆搜,出答案。
暴力出奇迹
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=1e5+100;
vector<int> vec[MAXN];//存边
int dep[MAXN],fa[MAXN],cs,blk[MAXN];
//blk Orange的时间 fa 父节点 dep 两个用处,见下面注释
int n,t,ans;
void dfs(int x,int depth,int fx)
{
dep[x]=depth;
for(int i=0;i<vec[x].size();i++){
int s=vec[x][i];
if(s==fx) continue;
fa[s]=x;dfs(s,depth+1,x);
}
}//预处理的dfs,先求出以1为根的向n的dep,然后方能求ts后现在的位置
//后面的用处是找土拨鼠的时间,存在dep里
void dfs1(int x,int depth,int fx)
{
blk[x]=depth/2;
for(int i=0;i<vec[x].size();i++){
int s=vec[x][i];
if(s==fx) continue;
dfs1(s,depth+1,x);
}
}//找Orange的时间,存在blk里
void getans(int x,int fx)
{
bool fl=0;
for(int i=0;i<vec[x].size();i++){
int s=vec[x][i];
if(s==fx) continue;fl=1;
if(dep[s]>=blk[s]){//不合法的点
ans=max(blk[x],ans);
continue;
}
getans(s,x);
}
if(!fl){
ans=max(ans,blk[x]);
}//叶节点
}//然后以当前位置为根,找到每条链能走的最远的地方
int main()
{
int x,y;
scanf("%d%d",&n,&t);
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
vec[x].push_back(y);
vec[y].push_back(x);
}
dfs(1,0,-1);
int gol=dep[n]-t,rt;//gol 走完ts后与n的距离 rt 根
if(gol<=0){puts("0");return 0;}//如果ts后已经到了,那么Orange就直接抓住了土拨鼠
for(int i=n,j=gol+1;j;i=fa[i],j--) rt=i;//找出t秒之后当前的位置,rt
memset(dep,0,sizeof(dep));
memset(blk,0,sizeof(blk));
dfs(rt,0,-1);//得出土拨鼠的时间
dfs1(n,1,-1);//得出Orange的时间
ans=-1;getans(rt,-1);//得出答案
printf("%d\n",ans);
}
END
这题可以只用一个dfs,然后思路差不多,只不过把时间换成是这个节点到两人的距离,用 l c a lca lca就可以过。其实没有什么本质的差别,但是我的做法还是被 D N d a l a o DNdalao DNdalao嫌弃了wuwuwu……