1787: [Ahoi2008]Meet 紧急集合

题目描述

题解:

这题首先能够确定这个交点属于任意两个点的lca中的一个。
那么我们就可以刷三次lca,并且求出交点,然后路径求和就好了。

代码如下:

#include<cstdio>
#include<string>
using namespace std;
const int maxn=500005;
int n,Q,tot,lnk[maxn],son[2*maxn],nxt[2*maxn],dep[maxn],f[maxn][20];
inline int read(){
    int x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
    return x;
}
void add(int x,int y) {son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;}
void dfs(int x,int fa) {
    for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa) {dep[son[j]]=dep[x]+1,f[son[j]][0]=x; dfs(son[j],x);}
}
void build(){
     for (int j=1;j<=19;j++)
     for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
}
int get(int x,int y){
    if (dep[x]<dep[y]) swap(x,y);
    for (int i=19;i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    if (x==y) return x;
    for (int i=19;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main(){
    n=read(),Q=read();
    for (int i=1;i<n;i++) {int x=read(),y=read(); add(x,y); add(y,x);}
    dep[1]=1; dfs(1,0); build();
    while (Q--){
        int x=read(),y=read(),z=read(),f1=get(x,y),f2=get(y,z),f3=get(x,z),ans;
        if (f1==f2) ans=f3; else if (f1==f3) ans=f2; else ans=f1;
        printf("%d %d\n",ans,dep[x]+dep[y]+dep[z]+3*dep[ans]-2*(dep[get(x,ans)]+dep[get(y,ans)]+dep[get(z,ans)]));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dyt_b/article/details/79937283