CF519E A and B and Lecture Rooms

题目描述

(A)(B)在准备参加编程比赛。

(A)(B)学习的大学的房间由走廊连接。大学一共有nn 个房间,由(n-1)条走廊连接,房间的编号是从(1)(n)的数字编号。

(A)(B)在大学的某些房间里进行比赛。在每场比赛之后,他们会一起在一个房间里讨论问题。(A)(B)希望这个讨论问题的房间到分别他们两个人比赛房间的距离相等。两个房间之间的距离指他们之间最短路的边数。

因为(A)(B)每天都在不一样的房间里比赛,所以他们请求你告诉他们在接下来比赛的(m) 天里可以用来讨论问题的房间有多少个?

输入输出格式

输入格式

第一行包括整数(n),其中((1 leq n leq 10^5)),表示房间数量。

接下来的(n-1)行描述所有的走廊。这(n-1)行中的第(i)行包括两个整数(a_i)(b_i),表示第ii 条走廊连接了房间(a_i)(b_i)

接下来的一行输入比赛的天数(m(1 leq m leq 10^5))

再接下来的(m)行,第(j)行包含两个整数(x_j)(y_j(1 leq x_j,y_j leq n)),表示比赛的第(j)(A)将在(x_j)房间比赛,(B)将在(y_j)房间比赛。

输出格式

在第(i(1 leq i leq m))行输出当天分别到(A)(B)比赛的房间距离相等的房间数量。

输入输出样例

输入样例#1:

4
1 2
1 3
2 4
1
2 3

输出样例#1:

1

输入样例#2:

4
1 2
2 3
2 4
2
1 2
1 3

输出样例#2:

0
2

思路:这道题……是道好题,题意是给你一棵树,对于每次询问,每个询问给出两个点,让你求有几个点到这两个点的距离是相等的,首先,每条边的边权是(1),因此每个点的深度就是它到根结点的距离,然后通过样例和自己手玩发现,如果它们到它们的(LCA)的距离之和是奇数,那么答案必然是(0),其次如果两个点深度是相同的,那么答案就是以它们以根结点为根的树的点的个数(即(n))减去以这两个点为根的子树的点的个数,还有一种情况,那就是深度不相同,则找一个这两点之间的中间结点,然后答案就是以这个中间结点为根的子树点的个数减去以这以两点深度较深的点为根的子树点的个数。求中间结点可以用类似求(LCA)(f)数组的方法来求。就是让较深的结点向上跳这两点距离的二分之一。

代码:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 100007
using namespace std;
int n,t,head[maxn],d[maxn],num,f[maxn][22],size[maxn];
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
struct node {
  int v,nxt;
}e[maxn<<1];
inline void ct(int u, int v) {
  e[++num].v=v;
  e[num].nxt=head[u];
  head[u]=num;
}
void dfs(int u, int fa) {
  for(int i=head[u];i;i=e[i].nxt) {
    int v=e[i].v;
    if(v!=fa) {
      f[v][0]=u;
      d[v]=d[u]+1;
      dfs(v,u);
      size[u]+=size[v];
    }
  }
}
inline int lca(int a, int b) {
  if(d[a]>d[b]) swap(a,b);
  for(int i=20;i>=0;--i)
  if(d[a]<=d[b]-(1<<i)) b=f[b][i];
  if(a==b) return a;
  for(int i=20;i>=0;--i)
  if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];
  return f[a][0];
}
int main() {
  n=qread();
  for(int i=1,u,v;i<n;++i) {
    u=qread(),v=qread();
    ct(u,v);ct(v,u);
  }
  for(int i=1;i<=n;++i) size[i]=1;
  dfs(1,0);
  for(int j=1;j<=20;++j)
  for(int i=1;i<=n;++i)
  f[i][j]=f[f[i][j-1]][j-1];
  t=qread();
  for(int i=1,u,v;i<=t;++i) {
    u=qread(),v=qread();
    if(d[u]<d[v]) swap(u,v);
    if((d[u]+d[v]-2*(lca(u,v)))&1) {printf("0
");continue;}
    int lc=lca(u,v),x=u; 
    int p=(d[u]+d[v]-2*d[lc])/2-1;
    for(int i=20;i>=0;--i) if(p&(1<<i)) u=f[u][i];
    if(d[x]==d[v]) {
      p=d[v]-d[lc]-1;
      for(int i=20;i>=0;--i) if(p&(1<<i)) v=f[v][i];
      printf("%d
",n-size[u]-size[v]);
    }
    else printf("%d
",size[f[u][0]]-size[u]);
  }
  return 0;
}
原文地址:https://www.cnblogs.com/grcyh/p/10153920.html