DTOJ3373 约会

58 篇文章 0 订阅

题目

题目描述

Vincent和他的大学GF不在同一个院系中,但他们每天都要约在校园中的同一个地方见面
THU的地图可以抽象为一个 n n n个结点的一棵树,即有 n n n个地点, n − 1 n-1 n1条无向边,每条边的长度为 1 1 1,任意两个地点之间是连通的树还能不连通!?
由于每天的课程不同,他们每天所在的位置也不同,第 i i i天,Vincent在地点 x i x_i xi,他的GF在地点 y i y_i yi
由于不能让某一方走的路程过多,所以他们约会的地点有个要求,必须与两人的位置之间的距离相等,距离指在树上的最短路径
请你帮Vincent算算每天他们有多少种可选的约会地点

输入格式

第一行一个整数 n n n
接下来 n − 1 n-1 n1行,每行两个整数 u u u v v v,表示树上有一条 u u u v v v之间的边
接下来一行一个整数 m m m,表示他们有 m m m天要约会见面
接下来 m m m行,每行两个整数 x i , y i x_i,y_i xi,yi,表示第 i i i天,他们各自的位置

输出格式

对于每一天,输出一行一个整数,表示第 i i i天可行的约会地点有多少个

样例

样例输入

4
1 2
1 3
2 4
1
2 3

样例输出

1

数据范围与提示

样例解释

约会地点 1 1 1是可行的

数据范围及约定

对于 25 % 25 \% 25%的数据, n , m ⩽ 100 n,m \leqslant 100 n,m100
对于 50 % 50 \% 50%的数据, n , m ⩽ 1 0 3 n,m \leqslant 10^3 n,m103
另外存在 20 % 20 \% 20%的数据,树是一条链
另外存在 15 % 15 \% 15%的数据,树是随机生成的
对于 100 % 100 \% 100%的数据, n , m ⩽ 1 0 5 n,m \leqslant 10^5 n,m105

题解

首先,以编号为 1 1 1的点为根
对于一组询问 x , y x,y x,y,如果 x x x的深度小于 y y y,那就交换他们的顺序
接着,求出它们的LCA,就可以求出链的长度
如果链的长度是偶数,那就没有中点,答案是 0 0 0
如果链的长度是奇数,就求出链的中点
如果中点是它们的LCA,那么深度比LCA小的节点和不包含 x x x y y y的LCA的子树是可行的约会地点
若中点不是LCA,那么深度小于中点的点都不是可行的约会地点,深度大于中点的节点用类似于上面的求法求出来就可以了
附上代码:

#include<iostream>
using namespace std;
int n,m,tot,head[100010],nxt[200010],to[200010],dep[100010],Fa[100010][25],size[100010];
void add(int a,int b)
{
	nxt[++tot]=head[a],head[a]=tot,to[tot]=b;
}
void dfs(int x,int fa)
{
	dep[x]=dep[fa]+1,size[x]=1,Fa[x][0]=fa;
	for(int i=1;i<=20;i++) Fa[x][i]=Fa[Fa[x][i-1]][i-1];
	for(int i=head[x];i;i=nxt[i]) if(to[i]^fa) dfs(to[i],x),size[x]+=size[to[i]];
}
int lca(int x,int y)
{
	for(int i=20;~i;i--) if(dep[Fa[x][i]]>=dep[y]) x=Fa[x][i];
	for(int i=20;~i;i--) if(Fa[x][i]^Fa[y][i]) x=Fa[x][i],y=Fa[y][i];
	if(x^y) return Fa[x][0];
	else return y;
}
int find(int x,int y)
{
	for(int i=20;~i;i--) if(y>>i&1) x=Fa[x][i];
	return x;
}
int main()
{
	cin>>n;
	for(int i=1,x,y;i<n;i++) cin>>x>>y,add(x,y),add(y,x);
	dfs(1,0),cin>>m;
	for(int i=1,x,y,len,LCA;i<=m;i++){
		cin>>x>>y;
		if(dep[x]<dep[y]) swap(x,y);
		LCA=lca(x,y),len=dep[x]+dep[y]-2*dep[LCA];
		if(len&1) cout<<0;
		else{
			len>>=1;
			int mid=find(x,len);
			if(mid==x) cout<<n;
			else if(mid==LCA) cout<<size[1]-size[find(x,len-1)]-size[find(y,len-1)];
			else cout<<size[mid]-size[find(x,len-1)];
		}
		cout<<endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值