JZOJ 5257. 小X的佛光 (Standard IO)

5257. 小X的佛光 (Standard IO)

Time Limits: 2000 ms Memory Limits: 524288 KB

Description

这里写图片描述

Input

这里写图片描述

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

这里写图片描述

Hint

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

题解

n 个城市n1条边,很明显是一颗树
画多几个图,就会发现可以用 lca 分类讨论

对于三个点 x,z,y ,要求的是 x>z y>z 重合部分的长度,即点的个数
有三种情况

设三点 lca 分别是 fxyfyzfxz
第一种是 fxz=fyz ,这样就是 z 的深度+/fxz的深度 +1
第二种是 fxy=fyz ,这样就是 z 的深度fxz的深度 +1
第三种是 fxz=fxy ,这样就是 z 的深度fyz的深度 +1

lca tarjan 会爆栈,虽然我之前写过手打栈版,但是由于太麻烦了,就用了倍增

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#define N 200010
using namespace std;

vector<long>map[N];
queue<long>que;
bool b[N];
long dep[N],fa[N][20];

void build(long x)
{   long now,to,i;
    que.push(x);
    while(!que.empty()){
        now=que.front();
        que.pop();
        b[now]=true;
        for(i=0;i<map[now].size();i++){
            to=map[now][i];
            if(!b[to]){
                fa[to][0]=now;
                dep[to]=dep[now]+1;
                que.push(to);
            }
        }
    }
}

long n;

void init()
{   long i,j;
    for(j=1;(1<<j)<=n;j++)
        for(i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
}

long lca(long x,long y)
{   long up;
    if(dep[x]>dep[y])
        swap(x,y);
    up=19;
    while(dep[y]>dep[x]){
        while(dep[y]-(1<<up)<dep[x]&&up>=0)
            up--;
        if(up<0)break;
        y=fa[y][up--];
    }
    up=19;
    while(x!=y){
        while(fa[x][up]==fa[y][up]&&up>=0)
            up--;
        if(up<0)break;
        x=fa[x][up];
        y=fa[y][up];
        up--;
    }
    if(x==y)
        return x;
    else
        return fa[x][0];
}

int main()
{   long m,q,x,y,z,fxy,fxz,fyz,i,ans;
    scanf("%ld%ld%ld",&n,&m,&q);
    for(i=1;i<n;i++){
        scanf("%ld%ld",&x,&y);
        map[x].push_back(y);
        map[y].push_back(x);
    }
    build(1);
    init();
    for(i=1;i<=m;i++){
        scanf("%ld%ld%ld",&x,&z,&y);
        fxy=lca(x,y);
        fxz=lca(x,z);
        fyz=lca(y,z);
        if(fxz==fyz&&fxz!=fxy)
            if(fxz==z)
                ans=dep[fxy]-dep[z]+1;
            else
                ans=dep[fxy]+dep[z]-dep[fxz]*2+1;
        else if(fxy==fyz&&fxz!=fxy)
            ans=dep[z]-dep[fxz]+1;
        else
            ans=dep[z]-dep[fyz]+1;
        printf("%ld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值