JZOJ 5257. 小X的佛光

18 篇文章 0 订阅
11 篇文章 0 订阅

Description

Description

Input

Input

Output

Output

Sample Input

3 3 1
1 2
2 3
1 2 3
1 1 3
3 1 3

Sample Output

1
1
3

Data Constraint

Data Constraint

Hint

样例2、3、4见所附文件

Solution

  • 题目给出一个无根树,于是我们先以 1 位根,将树转成有根树,可以发现这不影响答案。

  • 同时记录点的深度和父亲等信息,用倍增预处理出点的 Lca 信息。

  • 接着,对于一个询问,求出两两之间的 Lca ,分类讨论其摆布情况,通过深度算出答案即可。

  • 特别注意的是分类讨论情况繁琐,切勿漏判,时间复杂度为 O((N+Q) log N)

Code

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+1;
int tot;
int first[N],next[N<<1],en[N<<1];
int dep[N],f[N][18];
inline int read()
{
    int X=0,w=1; char ch=0;
    while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
inline int max(int x,int y)
{
    return x>y?x:y;
}
inline void insert(int x,int y)
{
    next[++tot]=first[x];
    first[x]=tot;
    en[tot]=y;
}
inline void dfs(int x)
{
    dep[x]=dep[f[x][0]]+1;
    for(int i=first[x];i;i=next[i])
        if(en[i]!=f[x][0])
        {
            f[en[i]][0]=x;
            dfs(en[i]);
        }
}
inline int lca(int x,int y)
{
    if(dep[y]>dep[x]) swap(x,y);
    for(int i=log2(dep[x]);i>=0;i--)
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=log2(dep[x]);i>=0;i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main()
{
    int n=read(),q=read(),num=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        insert(x,y);
        insert(y,x);
    }
    dfs(1);
    for(int j=1;j<=17;j++)
        for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    while(q--)
    {
        int a=read(),b=read(),c=read(),ans=0;
        int ab=lca(a,b),ac=lca(a,c),bc=lca(b,c);
        if(ab==b)
        {
            if(dep[ac]<=dep[b]) ans=1; else ans=dep[ac]-dep[b]+1;
        }else
        if(ab==a)
        {
            if(dep[bc]<=dep[a]) ans=dep[b]-dep[a]+1; else ans=dep[b]-dep[bc]+1;
        }else
        {
            if(ac==a) ans=dep[a]+dep[b]-2*dep[ab]+1; else
            if(bc==b) ans=1; else
            if(bc==c) ans=dep[b]-max(dep[c],dep[ab])+1; else
            if(ac==c)
            {
                ans=dep[b]-dep[ab]+1;
                if(dep[c]>dep[ab]) ans+=dep[c]-dep[ab];
            }else
            if(bc==ab && ab==ac) ans=dep[b]-dep[bc]+1; else
            if(dep[bc]>dep[ab]) ans=dep[b]-dep[bc]+1; else
            if(dep[ac]<dep[ab])
            {
                if(dep[ab]>dep[bc]) ans=dep[b]-dep[ab]+1; else
                    ans=dep[ab]+dep[c]-2*dep[ac]+1;
            }else
            if(dep[ac]>=dep[ab]) ans=dep[ac]+dep[b]-2*dep[ab]+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值