[ABC267F] Exactly K Steps

Problem Statement

You are given a tree with $N$ vertices. The vertices are numbered $1, \dots, N$, and the $i$-th ($1 \leq i \leq N - 1$) edge connects Vertices $A_i$ and $B_i$.

We define the distance between Vertices $u$ and $v$ on this tree by the number of edges in the shortest path from Vertex $u$ to Vertex $v$.

You are given $Q$ queries. In the $i$-th ($1 \leq i \leq Q$) query, given integers $U_i$ and $K_i$, print the index of any vertex whose distance from Vertex $U_i$ is exactly $K_i$. If there is no such vertex, print -1.

Constraints

  • $2 \leq N \leq 2 \times 10^5$
  • $1 \leq A_i \lt B_i \leq N \, (1 \leq i \leq N - 1)$
  • The given graph is a tree.
  • $1 \leq Q \leq 2 \times 10^5$
  • $1 \leq U_i, K_i \leq N \, (1 \leq i \leq Q)$
  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

$N$
$A_1$ $B_1$
$\vdots$
$A_{N-1}$ $B_{N-1}$
$Q$
$U_1$ $K_1$
$\vdots$
$U_Q$ $K_Q$

Output

Print $Q$ lines. The $i$-th ($1 \leq i \leq Q$) line should contain the index of any vertex whose distance from Vertex $U_i$ is exactly $K_i$ if such a vertex exists; if not, it should contain -1. If there are multiple such vertices, you may print any of them.


Sample Input 1

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

Sample Output 1

4
1
-1

  • Two vertices, Vertices $4$ and $5$, have a distance exactly $2$ from Vertex $2$.
  • Only Vertex $1$ has a distance exactly $3$ from Vertex $5$.
  • No vertex has a distance exactly $3$ from Vertex $3$.

Sample Input 2

10
1 2
2 3
3 5
2 8
3 4
4 6
4 9
5 7
9 10
5
1 1
2 2
3 3
4 4
5 5

Sample Output 2

2
4
10
-1
-1

对于一个点 \(u\),如果我们找到离他最远的点 \(v\),那么此时如果 \((u,v)\) 的距离还超不过 \(k\),肯定无解。否则,就在路径 \((u,v)\) 上寻找到那个离 \(u\) 刚好是 \(k\) 格的点就行了。

但是最远的点在哪里呢?有一个定理,就是一棵树上,离一个点最远的点一定是直径的两端点之一。

所以求出原来直径的两个端点 \((u',v')\),然后以他们两个分别为根,跑出一次倍增。询问的时候就可以看两个端点哪个离他更远,然后在对应的倍增数组上找到离他恰好为 \(k\) 的点。复杂度 \(O(nlogn+qlogn)\)

当然也可以用长剖卡到 \(O(nlogn+q)\),不过没必要。

#include<cstdio>
const int N=2e5+5;
int n,u,v,rt,fa[N][23],dp1[N],dp2[N],f[N][23],ans(-1),hd[N],e_num,q,k;
struct edge{
	int v,nxt;
}e[N<<1];
void add_edge(int u,int v)
{
	e[++e_num]=(edge){v,hd[u]};
	hd[u]=e_num;
}
void dfs(int x,int y,int dep)
{
	if(dep>ans)
		ans=dep,rt=x;
	for(int i=hd[x];i;i=e[i].nxt)
		if(e[i].v!=y)
			dfs(e[i].v,x,dep+1);
}
void sou(int x,int y)
{
	dp1[x]=dp1[y]+1,f[x][0]=y;
	if(dp1[x]>ans)
		ans=dp1[x],rt=x;
	for(int i=1;i<20;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(int i=hd[x];i;i=e[i].nxt)
		if(e[i].v!=y)
			sou(e[i].v,x);
}
void suo(int x,int y)
{
	dp2[x]=dp2[y]+1,fa[x][0]=y;
//	printf("%d %d\n",x ,dp2[x]);
	for(int i=1;i<20;i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=hd[x];i;i=e[i].nxt)
		if(e[i].v!=y)
			suo(e[i].v,x);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		add_edge(u,v);
		add_edge(v,u);
	}
	dfs(1,0,0);
	ans=0;
	sou(rt,ans=0);
	suo(rt,0);
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d%d",&u,&k);
		if(dp1[u]>k)
		{
			for(int i=0;i<20;i++)
				if(k>>i&1)
					u=f[u][i];
			printf("%d\n",u);
		}
		else if(dp2[u]>k)
		{
			for(int i=0;i<20;i++)
				if(k>>i&1)
					u=fa[u][i];
			printf("%d\n",u);
		}
		else
			puts("-1");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值