• 洛谷 P3398 仓鼠找sugar 题解


    先说一下题意:

    在一颗树上一个仓鼠从a走到b,一个他的基友从c走到d求他两个是不是会有相遇的地方。

    一道求lca的题目。

    这道题只看题目是很难找出规律的,但是一画图他的规律就很显然了

    可以发现如果两条路径如果相交那一对点的最近公共祖先一定在另一台的路径上

    不然如果相交那就这能两条边交叉,这在树中是不可能出现的
    否则就不是一棵树

    但是怎么确定这到底是不是回相遇的呢?

    可以先求出仓鼠目的地b和出发点a的最近公共祖先qwq和surger的

    目的地d和出发点c的最近公共祖先awa

    然后分别求出a和d,a和c,b和d,b和c的最近公共祖先来和

    前面求出的两个最近公共祖先的深度比较如果有一个这两个

    深度小那就是不可行的不然如果都比他深度深或者等于的话

    那就是可能遇见的

    但是怎么证明只要他们的最近公共祖先的深度大于等于awa和qwq

    那就是可行的呢?

    这个在三克油大佬的博客里面已经证明的很好啦,我就不多说了
    附上链接

    这里

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    const int Max = 100005;
    struct node
    {
    	int y,ne;
    }a[Max << 1];
    int head[Max];
    int f[Max][22];
    int tot = 0;
    void insert(int x,int y)
    {
    	a[++ tot].y = y;
    	a[tot].ne = head[x];
    	head[x] = tot;
    }
    bool use[Max];
    int de[Max];
    void dfs(int x)
    {
    	use[x] = true;
    	for(int i = head[x];i != 0;i = a[i].ne)
    	{
    		int ii = a[i].y;
    		if(use[ii] == false)
    		{
    			f[ii][0] = x;
    			de[ii] = de[x] + 1;
    			dfs(ii);
    		}
    	}
    }
    
    int lca(int x,int y)
    {
    	if(de[x] < de[y])swap(x,y);
    	for(int j = 20;j >= 0;j --)
    		if(de[f[x][j]] >= de[y])
    			x = f[x][j];
    	if(x == y)
    		return x;
    	for(int i = 20;i >= 0;i --)
    		if(f[x][i] != f[y][i])
    			x = f[x][i],y = f[y][i];
    	return f[x][0];
    }
    
    int main()
    {
    	int n,q;
    	int x,y;
    	scanf("%d%d",&n,&q);
    	for(int i = 1;i < n;++ i)
    	{
    		scanf("%d%d",&x,&y);
    		insert(x,y);
    		insert(y,x);
    	}
    	de[1] = 1;
    	dfs(1);
    	for(int j = 1;j <= 20;j ++)
    		for(int i = 1;i <= n;++ i)
    			f[i][j] = f[f[i][j - 1]][j - 1];
    	while(q --)
    	{
    		int aa,bb,cc,dd;
    		scanf("%d%d%d%d",&aa,&bb,&cc,&dd);
    		int ab = lca(aa,bb);
    		int cd = lca(cc,dd);
    		
    		//int ac = lca(aa,cc);
    		//int ad = lca(aa,dd);
    		//int bc = lca(bb,cc);
    		//int bd = lca(bb,dd);
    		int ans = max(de[lca(aa,cc)],de[lca(aa,dd)]);
    		ans = max(ans,de[lca(bb,cc)]);
    		ans = max(ans,de[lca(bb,dd)]);
    		if(ans >= de[ab] && ans >= de[cd])
    			cout<<"Y"<<endl;
    		else
    			cout<<"N"<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    NETCore EF 数据库连接正确nuget和MySql错误异常
    JS 对象属性名排序
    NET 在一个数组中查找另一个数组所在起始位置(下标从0开始,未找到返回-1)
    NET 判断是否为回文
    NET/Regex 处理连续空格
    NET 已知excel表格前面26个是a到z,27是aa28是ab,以此类推,N是多少
    Regex 首字母转大写/小写,全大写,全小写
    .NETCore下访问img、js等静态资源404解决办法
    WPF-后台代码使用Behavior
    Socket-服务器端与客户端互相通信
  • 原文地址:https://www.cnblogs.com/acioi/p/11524117.html
Copyright © 2020-2023  润新知