P3398 仓鼠找sugar (LCA 性质)

P3398 仓鼠找sugar (LCA 性质)

P3398 仓鼠找sugar

完成本题要找到一个性质,要发现如何判断两条路径相交的条件。

找条件的最好方式莫过于研究实例了。接下来给出几个实例:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

不难发现,红色路径总与蓝色路径相交,而且红色路径总是穿过蓝色路径的两端的 LCA.

于是我们可以猜测,当某一条路径经过另一条路径两端的 LCA 时,两条路径相交。

可以反证法证明:

假设在一棵树中,两条路径相交,相交的深度最浅结点不是其中一条路径的两端的 LCA .

那么意味着,相交最浅的结点都不是两条路径深度最浅的结点,于是这个结点将有两个父亲,与在一棵树中的条件矛盾,假设不成立,所以在一棵树中,两条路径相交的条件时某一条路径经过另一条路径深度最浅的结点,也就是路径两端的 LCA .

在这里插入图片描述

于是我们只要判断是否存在一条路径的最浅结点在另一条路径中就能得知二者是否相交。

判断方法也显然:

  1. 求出一条路径两端的 LCA ,令其为 P P P .
  2. 在另一条路径中,令其两端的结点为 u , v u,v u,v ,求 l c a ( u , P ) , l c a ( v , P ) {\rm lca}(u,P),{\rm lca}(v,P) lca(u,P),lca(v,P) ,求出的 LCA 中有一个是这条路径深度最浅的结点,有一个是 P P P 则证明 P P P 在这一条路径中。
bool Check(int x,int y,int lca_xy,int z)//倍增求 LCA
{
	if(dep[z] < dep[lca_xy]) return 0;
	if(dep[z] <= dep[x])
	{
//		if(x == z) return 1;
		for(int i = 22;i >= 0;i --)
		{
			if(x == z) return 1;
			if(dep[f[x][i]] >= dep[z]) x = f[x][i];
			if(x == z) return 1;
		}
	}
	if(dep[z] <= dep[y])
	{
//		if(y == z) return 1;
		for(int i = 22;i >= 0;i --)
		{
			if(y == z) return 1;
			if(dep[f[y][i]] >= dep[z]) y = f[y][i];
			if(y == z) return 1;
		}
	}
	return 0;
}

int main()
{
	scanf("%d%d",&n,&q);
	for(int i = 1;i < n;i ++)
	{
		scanf("%d%d",&x,&y);
		addedge(x,y);
	}
	prework(1,0);
	for(int i = 1;i  <= q;i ++)
	{
		scanf("%d%d%d%d",&a,&b,&c,&d);
		lca1 = GetLCA(a,b);//倍增求 LCA
		lca2 = GetLCA(c,d);
		flag = (Check(a,b,lca1,lca2) | Check(c,d,lca2,lca1));
		if(flag) printf("Y\n");
		else printf("N\n");
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值