DestinHistoire

 

BZOJ-1832 [AHOI2008]聚会(LCA)

题目描述

  有一棵 \(n(1\leq n\leq 5\times 10^5)\) 个点,\(n-1\) 条边的树,\(q(1\leq q\leq 5\times 10^5)\) 次询问,每次询问给出三个点 \(a,b,c\),在树上选择一个点 \(x\),使得 \(a,b,c\) 三点走到点 \(x\) 的距离之和最小,输出点 \(x\) 的编号和最小权值和。

分析

  三点的三个 \(\text{LCA}\) 分为两种情况:

  \(1.\) 三个 \(\text{LCA}\) 重合在同一点,此时重合点就是 \(x\)

  \(2.\) 两个 \(\text{LCA}\) 重合在同一点,另一个 \(\text{LCA}\) 孤立,此时孤立的 \(\text{LCA}\)\(x\)

  对于这两种情况,距离之和都是 \((dis(a,b)+dis(b,c)+dis(a,c))/2\)

代码

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int head[N],num_edge;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
struct Edge
{
    int to;
    int Next;
    int dis;
}edge[N<<1];
void add_edge(int from,int to,int dis)
{
    edge[++num_edge].to=to;
    edge[num_edge].dis=dis;
    edge[num_edge].Next=head[from];
    head[from]=num_edge;
}
int n,q,_log;
int f[N][20],dep[N]/*,dist[N]*/;
queue<int> Q;
void bfs()
{
    Q.push(1);
    dep[1]=1;
    while(!Q.empty())
    {
        int x=Q.front();
        Q.pop();
        for(int i=head[x];i;i=edge[i].Next)
        {
            int y=edge[i].to;
            if(dep[y])
                continue;
            dep[y]=dep[x]+1;
            //dist[y]=dist[x]+1;
            f[y][0]=x;
            for(int j=1;j<=_log;j++)
                f[y][j]=f[f[y][j-1]][j-1];
            Q.push(y);
        }
    }
}
int LCA(int x,int y)
{
    if(dep[x]>dep[y])
        swap(x,y);
    for(int i=_log;i>=0;i--)
        if(dep[f[y][i]]>=dep[x])
            y=f[y][i];
    if(x==y)
        return x;
    for(int i=_log;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
long long dis(int x,int y)
{
    return (long long)(dep[x]+dep[y]-2*dep[LCA(x,y)]);
}
int main()
{
    cin>>n>>q;
    _log=(int)(log(n)/log(2))+1;
    for(int i=1;i<=n-1;i++)
    {
        int x=read(),y=read();
        add_edge(x,y,1);
        add_edge(y,x,1);
    }
    bfs();
    while(q--)
    {
        int a=read(),b=read(),c=read(),x;
        if(LCA(a,b)==LCA(b,c))
            x=LCA(a,c);
        else if(LCA(a,b)==LCA(a,c))
            x=LCA(b,c);
        else if(LCA(b,c)==LCA(a,c))
            x=LCA(a,b);
        printf("%d %lld\n",x,(dis(a,b)+dis(b,c)+dis(a,c))/2);
    }
    return 0;
}

posted on 2020-11-18 23:59  DestinHistoire  阅读(108)  评论(0)    收藏  举报

导航