1. 程式人生 > 其它 >AT2063 [AGC005E] Sugigma: The Showdown 題解

AT2063 [AGC005E] Sugigma: The Showdown 題解

完全不會做。

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;
}