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");
}
}
标签:distance,given,ABC267F,dp1,int,Exactly,Vertex,leq,Steps
From: https://www.cnblogs.com/mekoszc/p/17001075.html