• 聚会


    https://loj.ac/problem/10136

    题目描述

      给出一棵(n)个点的不带权树,有(m)个询问,每次询问给出(3)个点,求到这三个点距离之和最小的点。

    思路

      这题其实有一点卡倍增求(LCA),最好还是用(RMQ)或树剖,不过我还是用倍增过了。我们只要先求出三个点中两两点的(LCA),再考虑对于这三个点(a、b、c),必定会有两个点是相同的,否则,我们必定可以选出一个(LCA),使得树分成左右两部分,各有一个(LCA),这样显然不存在。所以对于这两个点,我们考虑选出那个不重复的点,因为以这两个(LCA)为分割,必定一边有两个点,一边有一个点,不重复的点更靠近两个点,可以是答案更小。而最后答案就是(dep[x]+dep[y]+dep[z]-dep[a]-dep[b]-dep[c]),因为重复的点一定是不重复的点的(LCA)

    代码

    #include<iostream>
    using namespace std;
    const int N=5e5+10;
    
    static int nxt[N<<1],to[N<<1],tot,head[N];
    inline void add_edge(int x,int y)
    {
    	nxt[++tot]=head[x];
    	head[x]=tot;
    	to[tot]=y;
    }
    static int f[N][22],dep[N];
    inline void dfs(int u,int fa)
    {
    	dep[u]=dep[fa]+1;
    	for(register int i=0;i<20;i++)
    		f[u][i+1]=f[f[u][i]][i];
    	for(register int i=head[u];i;i=nxt[i])
    	{
    		int v=to[i];
    		if(v==fa)continue ;
    		f[v][0]=u;
    		dfs(v,u);
    	}
    }
    inline int LCA(int x,int y)
    {
    	if(dep[x]<dep[y])swap(x,y);
    	for(register int i=20;i>=0;i--)
    	{
    		if(dep[f[x][i]]>=dep[y])x=f[x][i];
    		if(x==y)return y;
    	}
    	for(register 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];
    }
    
    inline int read()
    {
    	int res=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    	return res*w;
    }
    inline void write(int x)
    {
    	if(x<0){putchar('-');x=-x;}
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    }
    inline void writeln(int x)
    {
    	write(x);
    	putchar('
    ');
    }
    
    int n,m,x,y,z,a,b,c;
    int main() 
    {
    //	freopen("a.in","r",stdin);
    //	freopen("a.out","w",stdout);
    	n=read(),m=read();
    	for(register int i=1;i<n;i++)
    	{
    		x=read(),y=read();
    		add_edge(x,y);add_edge(y,x);
    	}
    	dfs(1,0);
    	for(register int i=1;i<=m;i++)
    	{
    		x=read(),y=read(),z=read();
    		a=LCA(x,y),b=LCA(y,z),c=LCA(x,z);
    		if(dep[a]==dep[b])write(c);
    		else if(dep[a]==dep[c])write(b);
    		else write(a);
    		putchar(' ');
    		writeln(dep[x]+dep[y]+dep[z]-dep[a]-dep[b]-dep[c]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    隔列求和
    拆分工作表一表变多表(Excel代码集团)
    拆分工作表一表变多簿(Excel代码集团)
    用汇编的眼光看C++(之退出流程) 四
    房价预测——备忘
    备用——GIT操作
    .NET 包对不同框架的兼容性
    Mac 快捷键 备忘录
    C#用法笔记——备忘
    git分支切换提交修改
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11788899.html
Copyright © 2020-2023  润新知