description
solution
考虑将边拆分,边长
×
2
\times 2
×2
然后将
k
k
k步以内可以互相走到的点用并查集合并在一起
同一个连通块的关键点可以相互走到
然后对于询问的两个城市,
u
u
u向
v
v
v走
k
k
k步,
v
v
v向
u
u
u走
k
k
k步,然后判断是不是在同一个连通块,使用树上倍增
l
o
g
log
log做到
注意两点距离公共祖先是不是比
k
k
k小
如果是,那么有一方是需要走折线的,就是先走到祖先再往下面另一方走
code
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 500005
queue < pair < int, int > > q;
vector < int > G[maxn];
int n, k, r, Q;
int f[maxn], dep[maxn];
int fa[maxn][20];
bool vis[maxn];
void makeSet( int n ) {
for( int i = 1;i <= n;i ++ ) f[i] = i;
}
int find( int x ) {
return x == f[x] ? x : f[x] = find( f[x] );
}
void bfs() {
while( ! q.empty() ) {
int u = q.front().first, step = q.front().second;
q.pop();
if( step == k ) return;
for( int i = 0;i < G[u].size();i ++ ) {
int v = G[u][i];
int fu = find( u ), fv = find( v );
f[fv] = fu;
if( ! vis[v] ) {
vis[v] = 1;
q.push( make_pair( v, step + 1 ) );
}
}
}
}
void dfs( int u, int Fa ) {
fa[u][0] = Fa, dep[u] = dep[Fa] + 1;
for( int i = 1;i < 20;i ++ )
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for( int i = 0;i < G[u].size();i ++ ) {
int v = G[u][i];
if( v == Fa ) continue;
else dfs( v, u );
}
}
int LCA( int u, int v ) {
if( dep[u] < dep[v] ) swap( u, v );
for( int i = 19;~ i;i -- )
if( dep[fa[u][i]] >= dep[v] )
u = fa[u][i];
if( u == v ) return u;
for( int i = 19;~ i;i -- )
if( fa[u][i] != fa[v][i] )
u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int climb( int u, int d ) {
for( int i = 0;i < 20;i ++ )
if( 1 << i & d ) u = fa[u][i];
return u;
}
int main() {
scanf( "%d %d %d", &n, &k, &r );
int cnt = n;
for( int i = 1, u, v;i < n;i ++ ) {
scanf( "%d %d", &u, &v );
++ cnt;
G[u].push_back( cnt );
G[cnt].push_back( u );
G[cnt].push_back( v );
G[v].push_back( cnt );
}
makeSet( cnt );
for( int i = 1, key;i <= r;i ++ ) {
scanf( "%d", &key );
q.push( make_pair( key, 0 ) );
vis[key] = 1;
}
bfs();
dfs( 1, 0 );
scanf( "%d", &Q );
for( int i = 1, s, t;i <= Q;i ++ ) {
scanf( "%d %d", &s, &t );
int lca = LCA( s, t );
int len = dep[s] + dep[t] - ( dep[lca] << 1 );
if( len <= ( k << 1 ) ) printf( "YES\n" );
else {
int u = dep[s] - dep[lca] >= k ? climb( s, k ) : climb( t, len - k );
int v = dep[t] - dep[lca] >= k ? climb( t, k ) : climb( s, len - k );
if( find( u ) == find( v ) ) printf( "YES\n" );
else printf( "NO\n" );
}
}
return 0;
}