【gdgzezoi】Problem B: 一样远

【问题描述】

企鹅国的城市结构是一棵树,有N座城市和N-1条无向道路,每条道路都一样长。豆豆和豆沙准备去参加NOIP(National Olympiad in Informatics for Penguin),但是他们住在不同的地方,豆豆住在城市A,豆沙住在城市B。他们想找一个距离A和B一样远的集合地点,所以他们想知道有多少个城市满足这个要求?

由于他们会参加很多次NOIP,所以有很多个询问。

【输入格式】

第一行一个整数N代表城市个数。

接下来N-1行,每行两个数字F和T,表示城市F和城市T之间有一条道路。

接下来一行一个整数M代表询问次数。

接下来M行,每行两个数字A和B,表示这次询问的城市A和城市B(A可能与B相同)。

【输出格式】

输出M行,每行一个整数表示到A和B一样远的城市个数。

【输入样例1】

4

1 2

2 3

2 4

2

1 2

1 3

【输出样例1】

0

2

【输入样例2】

4

1 2

2 3

2 4

2

1 1

3 3

【输出样例2】

4

4

【数据范围】

对于30%的数据:N,M≤1000;

对于另外10%的数据:A=B;

对于另外30%的数据:保证树的形态随机;

对于100%的数据:1≤N,M≤100000。

思路

对于A的深度=B的深度,中点为A和B的LCA。

如果不等于,可以先用LCA求出A、B的距离,再在树上倍增求出AB的中点。

注意特判AB终点不存在的情况。

代码

#include<bits/stdc++.h>
#define N 100077 
using namespace std;
int n,m,fa[N][20],dep[N],siz[N];
struct E{int to,next;}e[N<<1];
int ls[N],cnt;
void add(int u,int v)
{
    e[++cnt]=(E){v,ls[u]},ls[u]=cnt;
}
void dfs(int u,int f)
{
    fa[u][0]=f,dep[u]=dep[f]+1,siz[u]=1;
    for(int i=1; i<=17; ++i) fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int i=ls[u]; i; i=e[i].next) if(e[i].to!=f) dfs(e[i].to,u),siz[u]+=siz[e[i].to];
}
int Lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=17; i>=0; --i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    if(x==y) return x;
    for(int i=17; i>=0; --i) if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int solve1(int x,int y)
{
    for(int i=17; i>=0; --i) if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];
    return n-siz[x]-siz[y];
}
int solve2(int x,int y,int lim)
{
    if(dep[x]<dep[y]) swap(x,y);
    int dep_x=dep[x];
    for(int i=17; i>=0; --i) if(dep_x-dep[fa[x][i]]<lim) x=fa[x][i];
    return siz[fa[x][0]]-siz[x];
}
int main()
{
    scanf("%d",&n);
    for(int i=1,x,y; i<n; ++i) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs(1,0);
    scanf("%d",&m);
    while(m--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        int lca=Lca(u,v),dis=dep[u]+dep[v]-2*dep[lca];
        if(dis==0) printf("%d\n",n);
        else if(dis&1) printf("0\n");
        else if(dep[u]==dep[v]) printf("%d\n",solve1(u,v));
        else printf("%d\n",solve2(u,v,dis>>1));
    }
}

发布了703 篇原创文章 · 获赞 392 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/100551987