codeforces 519E A and B and Lecture Rooms LCA倍增

Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

Description

A and B are preparing themselves for programming contests.

The University where A and B study is a set of rooms connected by corridors. Overall, the University has n rooms connected by n - 1corridors so that you can get from any room to any other one by moving along the corridors. The rooms are numbered from 1 to n.

Every day А and B write contests in some rooms of their university, and after each contest they gather together in the same room and discuss problems. A and B want the distance from the rooms where problems are discussed to the rooms where contests are written to be equal. The distance between two rooms is the number of edges on the shortest path between them.

As they write contests in new rooms every day, they asked you to help them find the number of possible rooms to discuss problems for each of the following m days.

Input

The first line contains integer n (1 ≤ n ≤ 105) — the number of rooms in the University.

The next n - 1 lines describe the corridors. The i-th of these lines (1 ≤ i ≤ n - 1) contains two integers ai and bi (1 ≤ ai, bi ≤ n), showing that the i-th corridor connects rooms ai and bi.

The next line contains integer m (1 ≤ m ≤ 105) — the number of queries.

Next m lines describe the queries. The j-th of these lines (1 ≤ j ≤ m) contains two integers xj and yj (1 ≤ xj, yj ≤ n) that means that on the j-th day A will write the contest in the room xj, B will write in the room yj.

Output

In the i-th (1 ≤ i ≤ m) line print the number of rooms that are equidistant from the rooms where A and B write contest on the i-th day.

Sample Input

Input
4
1 2
1 3
2 4
1
2 3
Output
1
Input
4
1 2
2 3
2 4
2
1 2
1 3
Output
0
2

Hint

in the first sample there is only one room at the same distance from rooms number 2 and 3 — room number 1.

思路:

题意:给你一棵有n个节点的树,m个询问,每个询问a,b,求树中到a,b距离相等的节点个数

我们先使得deg[a] >= deg[b]

首先,若a~b之间的距离为奇数的话,找不到唯一的中点,此时答案为0

(怎么求a~b之间的距离呢?预处理节点i到根的距离(此处为深度)deg[i],求出lcaq = lca(a,b);

那么dist(a,b) = deg[a] - deg[lcaq] + deg[b] - deg[lcaq];)

否则:找出ab路径的中点mid,calc(u, d)可以找出节点u的深度为d的祖先,也就是我们求出中点的深度就可以找出中点!

怎么求中点的深度dmid?通过画图可知:

dmid = dist(a,b) / 2  - deg[b] + 2 * deg[lcaq];

最终答案的计算:num[i]表示以节点i为根的子树的节点总数

若a和b的深度相同,那么ans = num[lcaq] - num[xa] - num[xb]; 其中xa是lcaq在a~lcaq的下一个节点,xb是lcaq在b~lcaq的下一个节点

若a和b深度不同,那么ans = num[mid] - num[k], 其中k表示ab的中点的下一位置(在a和b路径上靠近a的下一位置),画图可以理解。

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

const int N = 1e5 + 5;
struct edge {
    int v, to;
    edge() {};
    edge(int v, int to) : v(v), to(to) {};
}e[N << 1];
int head[N], num[N], deg[N], tot, n, m;
int p[N][30];

void init()
{
    memset(head, -1, sizeof head);
    memset(p, -1, sizeof p);
    tot = 0;
}
void addedge(int u, int v)
{
    e[tot] = edge(v, head[u]);
    head[u] = tot++;
}
void dfs(int u, int fa, int d)
{
    deg[u] = d; p[u][0] = fa; num[u] = 1;
    for(int i = head[u]; ~i; i = e[i].to) {
        int v = e[i].v;
        if(v != fa) {
            dfs(v, u, d + 1);
            num[u] += num[v];
        }
    }
}
void pre()
{
    for(int j = 0; (1 << j) <= n; ++j)
        for(int i = 1; i <= n; ++i) {
            if(p[i][j - 1] != -1)
            p[i][j] = p[ p[i][j - 1] ][j - 1];
    }
}

int calc(int u, int d) ///返回节点u的深度为d的祖先
{
    for(int j = 25; j >= 0; --j) {
        if(deg[u] - (1 << j) >= d) u = p[u][j];
    }
    return u;
}
int lca(int a, int b)
{
    a = calc(a, deg[b]);///使a和b处在同一层
    if(a == b) return a; ///若此时a和b相等,那么lca就是a
    ///否则a和b同时向上爬
    for(int j = 25; j >= 0; --j) {
        if(p[a][j] != -1 && p[a][j] != p[b][j]) {
            a = p[a][j];
            b = p[b][j];
        }
    }
    return p[a][0];
}
int main()
{
    while(~scanf("%d", &n))
    {
        init();
        int u, v;
        for(int i = 1; i < n; ++i) {
            scanf("%d%d", &u, &v);
            addedge(u, v);
            addedge(v, u);
        }
        dfs(1, -1, 0);
        pre();

        scanf("%d", &m);
        int a, b;
        while(m --)
        {
            scanf("%d%d", &a, &b);
            if(deg[a] < deg[b]) swap(a, b);
            if(a == b) { printf("%d\n", n); continue; }
            int lcaq = lca(a, b);
            int dist = deg[a] + deg[b] - 2 * deg[lcaq]; ///a和b之间的距离
            if(dist & 1) { puts("0"); continue; }
            if(deg[a] == deg[b]) { ///xa和xb分别是在a~lca和b~lca的路径上距离lca为1的点
                int xa = calc(a, deg[lcaq] + 1);
                int xb = calc(b, deg[lcaq] + 1);
                printf("%d\n", n - num[xa] - num[xb]);
            }
            else {
                int mid = dist / 2 - deg[b] + 2 * deg[lcaq]; ///mid为ab之间的路径的中点的深度
                printf("%d\n", num[ calc(a, mid) ] - num[ calc(a, mid + 1) ]);
            }
        }
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/orchidzjl/p/4850565.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值