zoukankan      html  css  js  c++  java
  • 【洛谷P4281】紧急集合 / 聚会【LCA】

    题目大意:

    题目链接:https://www.luogu.org/problemnew/show/P4281#sub
    给出一棵树,每次给出三个点x,y,zx,y,z,求哪一个点与这三个点的距离之和最近。


    思路:

    首先,很明显的一件事情是:给出一棵树上的三个点,这三个点中总有两个的LCALCA是一样的。

    证明:
    假设我们能找到一个点,这个点的左子树中有2个标记点,右子树中有1个标记点(或者左子树1个,右子树2个),那么很明显左子树中的两个点分别与右子树的点取LCALCA的结果是一样的,都是选择的点。
    那么如果我们找不到这样的点,那么就只有这三个点在一条链上可能。
    那么如果这三个点在一条链上,那么很明显在下面的两个点与在上面的点取LCALCA的结果是一样的。都是上面那个点。
    证毕。

    好吧这个证明并不严谨,但是再仔细想一想就会发现是对的。
    所以,答案很明显就出来了。三个LCALCA中不同的那个就是最佳位置。


    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 500100
    #define LG 20
    using namespace std;
    
    int n,m,tot,head[N],f[N][LG+1],dep[N],l1,l2,l3;
    
    struct edge
    {
    	int next,to;
    }e[N*2];
    
    int in;
    char ch;
    
    int read()  //快读,不加好像会T
    {
        in=0;
        while((ch=getchar())<=47||ch>=58);in=(in<<3)+(in<<1)+ch-48;
        while((ch=getchar())>=48&&ch<=57) in=(in<<3)+(in<<1)+ch-48;
        return in;
    }
    
    
    void add(int from,int to)
    {
    	e[++tot].to=to;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs(int x,int fa)
    {
    	dep[x]=dep[fa]+1;
    	for (int i=1;i<=LG;i++)
    	 f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=head[x];~i;i=e[i].next)
    	 if (e[i].to!=fa)
    	 {
    	 	f[e[i].to][0]=x;
    	 	dfs(e[i].to,x);
    	 }
    }
    
    int lca(int x,int y)
    {
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=LG;i>=0;i--)
    	 if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (int i=LG;i>=0;i--)
    	 if (f[x][i]!=f[y][i])
    	 {
    	 	x=f[x][i];
    	 	y=f[y][i];
    	 }
    	return f[x][0];
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	n=read();
    	m=read();
    	int x,y,z;
    	for (int i=1;i<n;i++)
    	{
    		x=read();
    		y=read();
    		add(x,y);
    		add(y,x);
    	}
    	dep[0]=-1;
    	dfs(1,0);
    	for (int i=1;i<=m;i++)
    	{
    		x=read();
    		y=read();
    		z=read();
    		l1=lca(x,y);
    		l2=lca(y,z);
    		l3=lca(x,z);  //求出组合的LCA
    		if (l1==l2) 
    		 printf("%d %d\n",l3,dep[x]+dep[y]-dep[l3]*2+dep[z]+dep[l3]-dep[l1]*2);
    		else if (l2==l3)
    		 printf("%d %d\n",l1,dep[y]+dep[z]-dep[l1]*2+dep[x]+dep[l1]-dep[l2]*2);
    		else if (l1==l3)
    		 printf("%d %d\n",l2,dep[x]+dep[z]-dep[l2]*2+dep[y]+dep[l2]-dep[l3]*2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    怎么把创业的风险降到最低
    反思:创业一开始并不需要重量级的产品
    口头承诺不如白纸黑字 技术大牛曹政(前4399核心员工)期权被坑的那些事
    idea配置tomcat去启动web项目
    Closeable释放资源
    Spring的SchedulingConfigurer实现定时任务
    thymeleaf js绑定多个变量参数
    Mysql concat() group_concat()用法
    枚举
    lambda之美
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998555.html
Copyright © 2011-2022 走看看