多询问 树上距离A,B相等的点数。

题目

A and B and Lecture Rooms(https://ac.nowcoder.com/acm/problem/110856)

题目大意

给你一棵有n个节点的树。
有m个询问。每次询问给你一个A,B。问树上到A,B节点距离相等的点有多少个。

输入

第一行包含整数n(1 ≤ n ≤ 10^5)。
接下来的n-1线描述了走廊。第i行(1≤ i≤≤ n - 1)包含两个整数ai和bi(1≤ ai, bi≤ n),ai和bi有一条边。
下一行包含整数m(1 ≤ m ≤ 10^5)-查询数。
接下来的m行描述查询。每行包含两个整数A和B(1≤ A, B≤ n)

样例

输入
4
1 2
2 3
2 4
2
1 2
1 3
输出
0
2

输出

对于每个询问输出有多少个节点到A和B的距离相等。

思路

我们分析如果存在这个点,这个点一定有一个在A-B的路径上。
如果路径长度为奇数就输出0。
如果路径长度为偶数。我们分析:
1.假设A的深度>B的深度

A~B的距离为2k,那么这个点一定是A的第k级祖先C。
可以满足的点就是C的子节点个数-A所在的链的所有节点(就是A的k-1祖先(4)的子树大小)。
siz[lca(A,k)]siz[lca(A,k1)]
2.假设假设A的深度=B的深度

这个就是nsiz[lca(A,k1)]siz[lca(B,k1)]

#include <bits/stdc++.h>
using namespace std;

vector<int> G[500005];
struct LCA{
    int d[500005], fa[500005][22], lg[500005], siz[500005];
    void init(int n, int root){//预处理
        for(int i = 1; i <= n; ++i){
            lg[i] = lg[i-1] + (1 << lg[i-1] == i);
        }
        dfs(root, 0);
    }
    void dfs(int now, int father){
        fa[now][0]=father; d[now]=d[father]+1; siz[now]=1;
        for(int i=1; i<=lg[d[now]]; ++i){
            fa[now][i]=fa[fa[now][i-1]][i-1];
        }
        for(auto x: G[now]){
            if(x!=father){
                dfs(x, now); siz[now]+=siz[x];
            }
        }
    }
    int lca(int x, int y){//LCA
        if(d[x]<d[y]) swap(x, y);
        while(d[x]>d[y]){
            x=fa[x][lg[d[x]-d[y]]-1];
        }
        if(x==y) return x;
        for(int k=lg[d[x]]-1; k>=0; --k){
            if(fa[x][k]!=fa[y][k]){
                x=fa[x][k], y=fa[y][k];
            }
        }
        return fa[x][0];
    }
    int dis(int a, int b){
        return d[a]+d[b]-2*d[lca(a, b)];
    }
    int getk(int f, int k){
        for(int i=20; i>=0; i--){
            if(k&(1<<i)){
                f=fa[f][i];
            }
        }
        return f;
    }
}lca;

int main(){
    int n, m, x, y;
    scanf("%d", &n);
    for(int i=2; i<=n; i++){
        scanf("%d%d", &x, &y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    lca.init(n, 1);
    scanf("%d", &m);
    while(m--){
        scanf("%d%d", &x, &y);
        int dis=lca.dis(x, y);
        if(x==y){
            printf("%d\n", n);
            continue;
        }
        if(dis%2){
            printf("%d\n", 0);
        }
        else{
            dis/=2;
            int f, ans=0;
            if(lca.d[x]<lca.d[y]){
                f=lca.getk(y, dis-1);
                ans=lca.siz[lca.fa[f][0]]-lca.siz[f];
            }
            else if(lca.d[x]>lca.d[y]){
                f=lca.getk(x, dis-1);
                ans=lca.siz[lca.fa[f][0]]-lca.siz[f];
            }
            else{
                int fa=lca.getk(x, dis-1);
                int fb=lca.getk(y, dis-1);
                ans=n-lca.siz[fa]-lca.siz[fb];
            }
            printf("%d\n", ans);
        }
    }

    return 0;
}
posted @   liweihang  阅读(145)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
Live2D
欢迎阅读『多询问 树上距离A,B相等的点数。』
点击右上角即可分享
微信分享提示