题目大意:
题目链接:https://jzoj.net/senior/#main/show/4805
思路:
由于是一棵树,那么无论从点要走到哪个点,陌生人到达那个点的路径都是唯一的。
所以可以枚举在哪个点相遇。
但是枚举的点也是有要求的。如果在到达这个点之前石神就被抓到了,那么这个点就不可能到达了。
所以可以采用序来枚举。如果在这个点被抓到了,那么就直接返回就可以了。
先求出三个点到所有点的距离(设为),然后按序枚举点。默认当石神到达这个点之后就不再移动。
陌生人移动到这个点的时间是,在这段时间内,石神移动、等待了共单位时间。那么总时间就是。
如何判断返回呢?
如果石神移动到点的时间(因为每一回合陌生人移动2次,而石神移动1次)大于陌生人移动到的时间,那么说明在之前陌生人就可以抓到石神,直接返回就可以了。
答案就是。
时间复杂度。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=200010;
int n,s,q,p,tot,ans,dis[4][N],head[N];
struct edge
{
int to,next;
}e[N*2];
void add(int from,int to)
{
e[++tot].to=to;
e[tot].next=head[from];
head[from]=tot;
}
void dfs(int x,int fa,int id)
{
for (int i=head[x];~i;i=e[i].next)
{
int y=e[i].to;
if (y!=fa)
{
dis[id][y]=dis[id][x]+1;
dfs(y,x,id);
}
}
}
void dfs_ans(int x,int fa)
{
if (dis[2][x]<dis[1][x]*2||dis[3][x]<dis[1][x]*2) return;
int ans_=min(dis[2][x]+(dis[2][x]+1+(!dis[2][x]))/2,dis[3][x]+(dis[3][x]+1+(!dis[3][x]))/2);
if (ans_>ans) ans=ans_;
for (int i=head[x];~i;i=e[i].next)
{
int y=e[i].to;
if (y!=fa) dfs_ans(y,x);
}
}
int main()
{
freopen("track.in","r",stdin);
freopen("track.out","w",stdout);
memset(head,-1,sizeof(head));
scanf("%d%d%d%d",&n,&s,&q,&p);
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(s,0,1);
dfs(q,0,2);
dfs(p,0,3);
dfs_ans(s,0);
printf("%d
",ans);
return 0;
}