description
点击查看题目
solution
考虑将边拆分,边长×2\times 2×2
然后将kkk步以内可以互相走到的点用并查集合并在一起
同一个连通块的关键点可以相互走到
然后对于询问的两个城市,uuu向vvv走kkk步,vvv向uuu走kkk步,然后判断是不是在同一个连通块,使用树上倍增logloglog做到
注意两点距离公共祖先是不是比kkk小
如果是,那么有一方是需要走折线的,就是先走到祖先再往下面另一方走
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;
}