A and B and Lecture Rooms CodeForces 519E 【LCA】

传送门
 

Description

在大学里,小A和小B是一对非常要好的朋友,他们经常一起参加比赛。现在,这个大学里有n个教室,这n个教室用n-1个走廊相互连接,因此学生可以从一个教室经过走廊走到任何其他的教室。

每天,小A和小B都要讨论一些问题。每次下课以后(小A和小B在不同的地方上课),小A和小B就相约去同一个教室讨论问题。小A和小B希望讨论的教室离他们现在各自所在的教室距离相等。两个教室之间的距离指的是他们的最短距离。

由于小A和小B每天都要讨论问题,所以他们希望你能帮助他们计算出在接下来的m天里,离他们各自所在的位置距离相等的教室有多少个。

Input

输入第一行是一个正整数n,表示教室的数量。1<=n<=10^ 5。接下来n-1行,每行两个数a和b,表示a和b之间有一条走廊相通。接下来是一个正整数m,表示天数,1<=m<=10^ 5。接下来m行,每行两个数x和y(1<=x,y<=n), 表示每天小A和小B各自所在的教室编号,x有可能等于y。

Output

输出m行,对于每天,输出离小A和小B距离相等的教室的数量。
 

思路:第一反应是这道题能做。我们知道给的是一棵无向边树,我们求点到 s和e距离相等点的数量。 我可以很容易得到一个结论,如果两个点之间的距离是奇数,那么很明显答案为0。我们就要讨论距离为偶数的情况,两个点之间的链上面必有一个中点到s和e的距离相等,这个点就是一个关键点(我们该关键点为x)。当LCA(s,e)= x,答案就等于 n 减去s 和 e 两个分支上总节点数。当LCA(s,e)!= x,则说明 LCA(s,e)是 x 的祖先,x 是 s 或 e 的祖先,那么答案等于以 x 为根的树的节点数减去x 的儿子(该儿子应该是 s 或 e 的祖先,也可能是 s 或者 e 本身)为根的树的节点数。


坑点:当s==e时,答案应该为n。

附上代码:

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=1e12;
const ll INF=0x3f3f3f3f3f3f;

int n,q;
struct node
{
    int e;
    int p;
} load[200005];
int head[100005],sign;

void add_edge(int s,int e)
{
    load[++sign]=node{e,head[s]};
    head[s]=sign;
}

int grand[100005][20],N;
int depth[100005];
int son[100005];

void init()
{
    N=log2(n);
    memset(grand,0,sizeof(grand));
    for(int i=1; i<=n; i++)
    {
        head[i]=-1;
        depth[i]=0;
        son[i]=1;
    }
    depth[0]=-1;
}

void dfs(int s,int pre)
{
    for(int i=1; i<=N; i++)
        grand[s][i]=grand[grand[s][i-1]][i-1];
    for(int i=head[s]; i!=-1; i=load[i].p)
    {
        int e=load[i].e;
        if(e!=pre)
        {
            depth[e]=depth[s]+1;
            grand[e][0]=s;
            dfs(e,s);
            son[s]+=son[e];
        }
    }
}

int get_lca(int a,int b)
{
    if(depth[a]>depth[b])
        swap(a,b);
    for(int i=N; i>=0; i--)
        if(depth[b]>=depth[a]&&depth[grand[b][i]]>=depth[a])
            b=grand[b][i];
    for(int i=N; i>=0; i--)
    {
        if(grand[a][i]!=grand[b][i])
        {
            a=grand[a][i];
            b=grand[b][i];
        }
    }
    return a==b?a:grand[b][0];
}

int jump(int now,int d)
{
    for(int i=N; i>=0; i--)
    {
        if(depth[now]>=d&&depth[grand[now][i]]>=d)
            now=grand[now][i];
    }
    return now;
}

int main()
{
    int s,e;
    scanf("%d",&n);
    init();
    for(int i=1; i<n; i++)
    {
        scanf("%d %d",&s,&e);
        add_edge(s,e);
        add_edge(e,s);
    }
    dfs(1,-1);
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d %d",&s,&e);
        if(s==e)
        {
            printf("%d\n",n);
            continue;
        }
        int x=get_lca(s,e);
        int len=depth[s]+depth[e]-2*depth[x];
        if(len&1)
            printf("0\n");
        else
        {
            int adv=len/2;
            int a=depth[s]-depth[x];
            int b=depth[e]-depth[x];
            if(a==b)
            {
                int c=jump(s,depth[x]+1);
                int d=jump(e,depth[x]+1);
                printf("%d\n",n-son[c]-son[d]);
            }
            else
            {
                if(a>b)
                    x=jump(s,depth[s]-adv+1);
                else
                    x=jump(e,depth[e]-adv+1);
                printf("%d\n",son[grand[x][0]]-son[x]);
            }
        }
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值