您的位置:首页 > 其它

[CodeForces519E]A and B and Lecture Rooms(lca)

2016-10-30 15:04 429 查看

题目描述

传送门

题意:求树上到某两点距离相等的点有多少个。

题解

如果这两个点不存在中点(距离不为偶数),答案显然为0。

由于树上的路径是唯一的,那么这x,y的中点一定满足条件,同时和这个中点相连的、并且到这个中点的路径不经过xy这条树链上的点都满足题意。那么我们可以用倍增求出这两个点的中点,然后用size什么的计算一下就行了。

注意根据xylca的位置要分情况讨论,细节不少,所以一定要写对拍!!!

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 100005
#define sz 17

int n,m,x,y;
int tot,point
,nxt[N*2],v[N*2];
int f
[sz+5],h
,size
;
struct hp{int pre,pt;};

void addedge(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void build(int x,int fa,int dep)
{
h[x]=dep; size[x]=1;
for (int i=1;i<sz;++i)
{
if ((h[x]-(1<<i))<1) break;
f[x][i]=f[f[x][i-1]][i-1];
}
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
f[v[i]][0]=x;
build(v[i],x,dep+1);
size[x]+=size[v[i]];
}
}
int lca(int x,int y)
{
if (h[x]<h[y]) swap(x,y);
int k=h[x]-h[y];
for (int i=0;i<sz;++i)
if ((1<<i)&k) x=f[x][i];
if (x==y) return x;
for (int i=sz-1;i>=0;--i)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
hp find(int x,int high)
{
int xx=x;
for (int i=sz-1;i>=0;--i)
while (h[f[x][i]]>high) xx=x,x=f[x][i];
xx=x,x=f[x][0];
hp ans;ans.pre=xx,ans.pt=x;
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;++i)
{
scanf("%d%d",&x,&y);
addedge(x,y);
}
build(1,0,1);
scanf("%d",&m);
for (int i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
if (h[x]<h[y]) swap(x,y);
if (x==y)
{
printf("%d\n",n);
continue;
}
int r=lca(x,y);
int len=h[x]-h[r]+h[y]-h[r];
if (len%2)
{
puts("0");
continue;
}
len/=2;
int high=h[x]-len;
if (high==h[r])
{
hp date1=find(x,high);
hp date2=find(y,high);
printf("%d\n",n-size[r]+size[r]-size[date1.pre]-size[date2.pre]);
}
else
{
hp date=find(x,high);
printf("%d\n",size[date.pt]-size[date.pre]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: