[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]); } } } } }