HYSBZ 1787 Meet 紧急集合

题意:
给定一些点和连通它们的边,三个人在站在不同的点上,要集合到同一点上去,问最小的总步数
题解:
①一个关于LCA的题
②记住一个结论:三个点的最小距离点等于两两的LCA中与其他两个LCA不同的LCA
③然后就没了

#pragma GCC optimize (2)
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 500010
#define abs(x) ((x)>0?(x):-(x))
using namespace std;
struct Edge{
        int to,next;
}a[maxn<<1];
int n,m;
int head[maxn],cnt;
int deep[maxn],prt[maxn],size[maxn],son[maxn];
int Time,Dfn[maxn],pos[maxn],top[maxn];
void Init();
void Insert(int,int);
void DFS1(int,int,int);
void DFS2(int,int);
int LCA(int,int);
void Solve(int,int,int);
int Dis(int,int);
signed main(){
        // freopen("in.cpp","r",stdin);
        Init();
        return 0;
}
void Init(){
        scanf("%d%d",&n,&m);
        int x,y,z;
        for(int i=1;i<n;i++){
                scanf("%d%d",&x,&y);
                Insert(x,y);Insert(y,x);
        }
        DFS1(1,0,1);
        DFS2(1,1);
        while(m--){
                scanf("%d%d%d",&x,&y,&z);
                Solve(x,y,z);
        }
}
void Solve(int x,int y,int z){
        int a=LCA(x,y),b=LCA(x,z),c=LCA(y,z);
        int prt;
        if(a==b)prt=c;
        else if(a==c)prt=b;
        else prt=a;
        printf("%d %d\n",prt,Dis(x,prt)+Dis(y,prt)+Dis(z,prt));
}
int Dis(int x,int y){
        int prt=LCA(x,y);
        return deep[x]+deep[y]-2*deep[prt];
}
void Insert(int x,int y){
        a[++cnt].to=y;
        a[cnt].next=head[x];
        head[x]=cnt;
}
void DFS1(int x,int prt,int deep){
        ::deep[x]=deep;
        ::prt[x]=prt;
        ::size[x]=1;
        for(int i=head[x];i;i=a[i].next){
                int y=a[i].to;
                if(y==prt)continue;
                DFS1(y,x,deep+1);
                size[x]+=size[y];
                if(size[y]>size[son[x]])son[x]=y;
        }
}
void DFS2(int x,int top){
        ::Dfn[x]=++Time;
        ::top[x]=top;
        ::pos[Time]=x;
        if(son[x])DFS2(son[x],top);
        for(int i=head[x];i;i=a[i].next){
                int y=a[i].to;
                if(y==prt[x]||y==son[x])continue;
                DFS2(y,y);
        }
}
int LCA(int x,int y){
        while(top[x]!=top[y]){
                if(deep[top[x]]<deep[top[y]])std::swap(x,y);
                x=prt[top[x]];
        }
        if(deep[x]<deep[y])return x;
        return y;
}

 

转载于:https://www.cnblogs.com/holy-unicorn/p/9510220.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值