[Contest1351]一样远

题面

Description

【问题描述】

企鹅国的城市结构是一棵树,有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。

题意

有一颗树,每次选两个点,问你树上距离这两个点距离相等的点有几个。

题解

分类讨论一下:

①两个点相同,答案为$n$

②两个点与$lca$的距离之和(见下图)为奇数,不存在符合要求的点,答案为0

③除去上面两种情况,若两点距离相等,答案为$n$-两点路径上比$lca$深度大1的点的$size$

④两点深度不一样,记录深度较大的点往上跳$len$个点的点(中点)$x$和往上跳$len-1$个点的点$y$($len$指两点与$lca$的距离之和),答案为$size_{x}-size_{y}$

完事儿,上代码

#include<iostream>
using namespace std;
const int N=1e5+5;
int n,head[N],m,siz[N],f[N][25],d[N],cnt;
struct edge{
	int v,next;
}e[N<<1];
void add(int u,int v){
	e[++cnt]=(edge){v,head[u]};
	head[u]=cnt;
}
void dfs(int u,int fa){
	siz[u]=1;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].v;
		if(v==fa)continue;
		f[v][0]=u;
		d[v]=d[u]+1;
		dfs(v,u);
		siz[u]+=siz[v];
	}
}
int lca(int x,int y){
	if(d[x]<d[y])swap(x,y);
	for(int i=20;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
	if(x==y)return x;
	for(int i=20;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	dfs(1,0);
	for(int i=1;i<=20;i++){
		for(int j=1;j<=n;j++){
			f[j][i]=f[f[j][i-1]][i-1];
		}
	}
	scanf("%d",&m);
	while(m--){
		int u,v;
		scanf("%d%d",&u,&v);
		if(u==v)printf("%d\n",n);//情况1
		else{
			int x=lca(u,v);
			int len=d[u]+d[v]-2*d[x];
			if(len%2)printf("0\n");//情况2
			else{
				if(d[u]==d[v]){//情况3
					int y=u,z=v;
					for(int i=20;i>=0;i--)if(d[f[y][i]]>d[x])y=f[y][i];
					for(int i=20;i>=0;i--)if(d[f[z][i]]>d[x])z=f[z][i];
					printf("%d\n",n-siz[y]-siz[z]);
				}
				else{//情况4
					if(d[u]<d[v])swap(u,v);
					len/=2;//注意
					int y=u,z=u;
					for(int i=20;i>=0;i--)if((len-1)&(1<<i))y=f[y][i];
					for(int i=20;i>=0;i--)if(len&(1<<i))z=f[z][i];
					printf("%d\n",siz[z]-siz[y]);
				}
			}
		}
	}
}

  

 

posted @ 2019-08-26 14:40  Evan704  阅读(162)  评论(0编辑  收藏  举报