【刷题】【LCA】紧急集合/聚会

给你一棵树,求三个点到哪个点的距离和最近,且求出距离

挺好证的,是三个LCA中矮的那个,

但是这题需要卡常技巧,QAQ

以后还是要养成加上卡常技巧的习惯,20分啊

#include<cstdio>
#include<cstdlib>
#include<vector>
using namespace std;
int n,m;
const int N=500003;
int tot,head[N];
struct node
{
    int v,nx;
}e[N<<1];
void add(int u,int v)
{
    e[++tot].v =v,e[tot].nx =head[u],head[u]=tot;
    e[++tot].v =u,e[tot].nx =head[v],head[v]=tot;
}
int fa[N][20],dep[N];

inline int read()
{
    int x=0;char c=getchar();
    while(c<'0' || c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x;
}

void dfs(int rt,int f)
{
    dep[rt]=dep[f]+1;
    fa[rt][0]=f;
    for(int i=1;i<20 && fa[rt][i-1];i++)
        fa[rt][i]=fa[fa[rt][i-1]][i-1];
    
    for(int i=head[rt];i;i=e[i].nx )
        if(e[i].v !=f) 
            dfs(e[i].v ,rt);
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])
        x+=y,y=x-y,x-=y;
    int dis=dep[x]-dep[y];
    for(int i=1,j=0;i<=dis;i<<=1,j++)
        if(dis&i) x=fa[x][j];
    if(x==y) return x;
    
    for(int i=19;~i;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i]; 
    return fa[x][0];
}

int main()
{
    n=read(),m=read();
    int u,v,w;
    for(int i=1;i<n;i++)
        u=read(),v=read(),add(u,v);
    dfs(1,0);   
    
    while(m--)
    {
        u=read(),v=read(),w=read();
        int a=LCA(u,v),b=LCA(u,w),c=LCA(v,w);
        
        int ans=dep[u]+dep[v]+dep[w],pos;
        if(dep[a]==dep[b] ) 
            ans-=dep[a]*2+dep[c],pos=c;
        else if(dep[a]==dep[c])
            ans-=dep[a]*2+dep[b],pos=b;
        else ans-=dep[b]*2+dep[a],pos=a;
        printf("%d %d\n",pos,ans);
    }
    
    return 0;
} 
View Code

猜你喜欢

转载自www.cnblogs.com/xwww666666/p/11668461.html