前言
要知道怎么判-1,接下来就好办许多了。
题目大意
一个有红边和蓝边的图,只保留红边或蓝边都是一颗树。
现在A和B初始都在一个点上,轮流进行,A先操作。
A每次可以不动或沿着相邻的红边走到另一节点。
B类似,但只能走蓝边。
A和B相遇游戏结束。
A要最大化游戏时间,B要最小化游戏时间,若A永远不会被B抓到输出-1。
做法
当A到达一条红树上的边(x,y)的端点时(这条边满足x和y在蓝树的距离大于2),B还没抓到A,显然就-1了。
发现除了这种情况A都会被抓到,因为只剩下距离为1和2的边。
以B的初始点为根,发现A每次就是往子树逃,或往兄弟逃,或往父亲逃。只要B步步下潜,就能抓到A。当A和B相距为1,A无法通过往上跑或往兄弟跑来逃脱(往父亲跑下一步也被抓了)。
删除红树上满足A一旦到达就会-1的那些边,然后做bfs求出A能能跑到的点(即到达该点前不会被B抓),A一定会选择在蓝树中深度最大的,然后待在那弃疗。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=200000+10;
int h[maxn],go[maxn*4],nxt[maxn*4],co[maxn*4],e[maxn][2];
int dfn[maxn],low[maxn],dep[maxn],d[maxn],dl[maxn],fa[maxn];
bool bz[maxn],pd[maxn];
int i,j,k,l,t,n,m,x,y,tot,top,ans,head,tail;
void add(int x,int y,int z){
go[++tot]=y;
co[tot]=z;
nxt[tot]=h[x];
h[x]=tot;
}
void dfs(int x,int y){
fa[x]=y;
dfn[x]=++top;
int t=h[x];
while (t){
if (co[t]&&go[t]!=y){
dep[go[t]]=dep[x]+1;
dfs(go[t],x);
}
t=nxt[t];
}
low[x]=++top;
}
bool check(int x,int y){
if (dfn[x]>dfn[y]) swap(x,y);
if (dfn[x]<=dfn[y]&&low[x]>=low[y]) return dep[y]-dep[x]>2;
if (fa[x]==fa[y]) return 0;else return 1;
}
void bfs(){
int now,t;
pd[x]=1;
dl[tail=1]=x;
while (head<tail){
now=dl[++head];
t=h[now];
while (t){
if (!co[t]&&!pd[go[t]]){
d[go[t]]=d[now]+1;
if (d[go[t]]<dep[go[t]]){
pd[go[t]]=1;
dl[++tail]=go[t];
}
}
t=nxt[t];
}
}
}
int main(){
scanf("%d%d%d",&n,&x,&y);
fo(i,1,n-1){
scanf("%d%d",&j,&k);
//add(j,k,0);add(k,j,0);
e[i][0]=j;e[i][1]=k;
}
fo(i,1,n-1){
scanf("%d%d",&j,&k);
add(j,k,1);add(k,j,1);
}
dfs(y,0);
fo(i,1,n-1){
j=e[i][0];k=e[i][1];
if (check(j,k)) bz[j]=bz[k]=1;
else{
add(j,k,0);
add(k,j,0);
}
}
bfs();
fo(i,1,n){
if (pd[i]&&bz[i]){
printf("-1\n");
return 0;
}
else if (pd[i]) ans=max(ans,dep[i]*2);
}
printf("%d\n",ans);
}