AT2063 [AGC005E] Sugigma: The Showdown 题解

Link.

ATcoder
Luogu

Description.

完全不会做。

Alice 和 Bob 在打隔膜,有两棵树,分别命名为 A 树和 B 树。
两棵树上分别有两颗棋子,每次 Alice 和 Bob 分别可以移动棋子到相邻的节点。
Bob 想追上 Alice 的棋子即让他们棋子所在节点编号相同,Alice 则不希望。
问最大步数,或输出 -1 代表永远也追不上。

Solution.

先考虑追不上的情况,显然是 Alice 只需要轻轻一步,就可以在 B 树上跳很远,Bob 顾左不顾右,追不上。
抽象地说,就是 A 树上存在一对相邻的节点,它们在 B 树上距离大于等于三,且 Alice 在被 Bob 追上前能到达它。

接着考虑 Alice 能到达哪些点,注意这题中 Alice 和 Bob 可以原地等待。
所以 Alice 是无法越过 Bob 的,即相对位置一定不变,否则 Alice 就已经无敌了。
(手模以下我们会发现如果 Alice 步长为 2,那 Bob 必定可以等在 Alice 要到的两个点 “守株待兔”。
同时,如果 Alice 想让 Bob 猜不到他下一步会往哪走,Bob 就可以原地等待。
Alice 不可能使用 “迂回” 的战略,因为如果他迂回,Bob 往他那个方向继续追,Alice 要么无法回来,要么直接被困死。
所以 Bob 会 “步步相逼”,把 Alice 逼入死胡同。
以上分析的出的结论就是,如果 Alice 走直线到这个点所用时间小于等于 Bob 的,那 Alice 必然到不了这个点。

所以我们首先判断一下每个点是不是 “Alice 无敌点”,然后 Alice 按照向所有可以走到的方向前进。
Alice 必定会找到一个可以走到的位置,然后在那里原地等死,所以只需要找到 Bob 走到 Alice 可达点的最长距离即可。

Coding.

判断两个点距离是否大于三我竟然直接用了个倍增 LCA,不愧是我!

点击查看逊人代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}/*}}}*/
const int N=200005;struct edge{int to,nxt;}e[N<<1];int et,head[N];
int n,X,Y,da[N],db[N],fr[N],tw[N],f[N][20],rs;char fg[N];
inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
inline void dfs0(int x,int fa)
{
	f[x][0]=fa;for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) db[e[i].to]=db[x]+1,dfs0(e[i].to,x);
}
inline int LCA(int x,int y)
{
	if(db[x]<db[y]) swap(x,y);
	for(int i=19;~i;i--) if(db[f[x][i]]>=db[y]) x=f[x][i];
	for(int i=19;~i;i--) if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
	return x^y?f[x][0]:x;
}
inline int dis(int x,int y) {return db[x]+db[y]-(db[LCA(x,y)]<<1);}
inline void dfs1(int x,int fa)
{
	if(fg[x]) puts("-1"),exit(0);else rs=max(rs,db[x]);
	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
		{da[e[i].to]=da[x]+1;if(da[e[i].to]<db[e[i].to]) dfs1(e[i].to,x);}
}
signed main()
{
	read(n),read(X),read(Y);for(int i=1;i<n;i++) read(fr[i]),read(tw[i]);
	for(int i=1,x,y;i<n;i++) read(x),read(y),adde(x,y),adde(y,x);
	dfs0(Y,0);for(int i=1;i<n;i++) if(dis(fr[i],tw[i])>2) fg[fr[i]]=fg[tw[i]]=1;
	et=0,memset(head,0,sizeof(head));for(int i=1;i<n;i++) adde(fr[i],tw[i]),adde(tw[i],fr[i]);
	return dfs1(X,0),printf("%d\n",rs<<1),0;
}
posted @   Peal_Frog  阅读(125)  评论(1编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示

目录导航