2019 11/11 欢乐的爆零赛 T3 相遇游戏 题解

题目大意

何老板与郃德君在玩一款有趣的游戏,游戏虽然简单,他俩仍乐此不疲。
游戏在一个n个节点的地图上进行。游戏地图上有n-1条红色边,图中任意两点可通过红色边相互到达。地图上还有n-1条蓝色边,图中任意两点可通过蓝色边相互到达。
游戏开始时,何老板在x号点,郃德君在y号点。两人轮流操作。每一次操作,玩家可以移动到相邻的点,或者原地不动。何老板只能沿红色边移动,郃德君只能沿蓝色边移动。
如果某一刻,两人位于同一个节点(相遇),游戏结束。如果游戏在第i次操作结束,游戏得分为i。何老板想使得游戏得分尽可能大,郃德君想使游戏得分尽可能小。
游戏双方都很聪明,输出最终的游戏得分。

第一行,三个整数n,x,y
接下来n-1行,每行两个整数,表示一条红色边的两个端点
接下来n-1行,每行两个整数,表示一条蓝色边的两个端点

如果能在有限步内结束游戏,输出得分,否则输出-1

样例
4 1 2
1 2
1 3
1 4
2 1
2 3
1 4

输出:4

3 3 1
1 2
2 3
1 2
2 3

输出:4

4 1 2
1 2
3 4
2 4
1 2
3 4
1 3

输出:2

4 2 1
1 2
3 4
2 4
1 2
3 4
1 3

输出:-1

5 1 2
1 2
1 3
1 4
4 5
2 1
1 3
1 5
5 4

输出:6

思路

显然我们需要建两个独立的树,何老板为red_tree,hdhd为blue_tree
对于这两个树,根节点分别为x,y.
则可预处理出hdhd与何老板到达每个节点的时间(用普通的dfs即可)
如果hdhd比何老板先到i节点,那么何老板一定不可以去i节点。
反之ans=max(ans,2*hdhd到达i节点的时间)

那么-1如何判断呢?

在这里插入图片描述假定老板目前在1号节点,hdhd在4号节点。
老板先手仅可以去2否则会被hdhd直接抓住。
那么hdhd仅可以选择前往3节点上。
那么何老板又会回到1号节点
会一直循环下去…

若3 4 中只有一个节点呢?
何老板会被直接抓住,游戏结束。

所以-1的成立条件为dis(u,v)>2(u,v为原图3,4这类的节点)
dis(u,v)用lca算即可
即dis(u,v)=depth[u]+depth[v]-2*depth[lca(u,v)]

附代码

#include<stdio.h>
#include<bits/stdc++.h>
#define maxn 200005
#define inf 1e9
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
{
	char t=GC;
	int x=0;
	while(!isdigit(t)) t=GC;
	while(isdigit(t)) x=x*10+t-48,t=GC;
	return x;
}

using namespace std;

int red_cnt,red_ey[maxn*2],red_elast[maxn],red_ne[maxn*2];
void add_red_edge(int x,int y){
	red_cnt++;
	red_ey[red_cnt]=y;
	red_ne[red_cnt]=red_elast[x];
	red_elast[x]=red_cnt;
}
int blue_cnt,blue_ey[maxn*2],blue_elast[maxn],blue_ne[maxn*2];
void add_blue_edge(int x,int y){
	blue_cnt++;
	blue_ey[blue_cnt]=y;
	blue_ne[blue_cnt]=blue_elast[x];
	blue_elast[x]=blue_cnt;
}
int f[maxn][20],n,x,y;
inline void go_up(int &p,int x)
{
	static int s=ceil(log2(n));
	for(int i=0;i<=s;++i)if(x&1<<i) p=f[p][i];
	return;
}
int red_depth[maxn],blue_depth[maxn];
void Dfs(int u,int fa){
	f[u][0]=fa;
	int k=ceil(log2(n));
	for(int i=1;i<=k;i++)
		f[u][i]=f[f[u][i-1]][i-1];
	blue_depth[u]=blue_depth[fa]+1;
	for(int i=blue_elast[u];i;i=blue_ne[i]){
		int v=blue_ey[i];
		if(v!=fa){
			Dfs(v,u);
		}
	}
	return;
}
int lca(int u,int v)
{
	if(blue_depth[u]<blue_depth[v]) swap(u,v);
	go_up(u,blue_depth[u]-blue_depth[v]);
	if(u==v) return u;
	int s=ceil(log2(n));
	for(int i=s;i>=0;i--){
		if(f[u][i]!=f[v][i]){
			u=f[u][i];
			v=f[v][i];
		}
	}
	return f[u][0];
}
void dfs(int u,int fa){
	red_depth[u]=red_depth[fa]+1;
	for(int i=red_elast[u];i;i=red_ne[i]){
		int v=red_ey[i];
		if(v!=fa&&red_depth[u]<blue_depth[u]){
			int LCA=lca(u,v);
			int Dep=blue_depth[u]+blue_depth[v]-2*blue_depth[LCA];
			if(Dep>2){
				printf("-1\n");
				exit(0);
			}
			dfs(v,u);
		}
	}
	return;
}
void init(){
	Dfs(y,0);
	for (int i=1;i<=n;i++) red_depth[i]=inf;
	dfs(x,0);
}
void sc(){
	scanf("%d%d%d",&n,&x,&y);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add_red_edge(u,v);
		add_red_edge(v,u);
	}
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add_blue_edge(u,v);
		add_blue_edge(v,u);
	}
}
void work(){
	int Ans=0;
	for(int i=1;i<=n;i++){
		red_depth[i]--;
		blue_depth[i]--;
		if(red_depth[i]<=blue_depth[i]){
			Ans=max(Ans,2*blue_depth[i]);
		}
	}
	printf("%d\n",Ans);
}
int main(){
	sc();
	init();
	work();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值