【CF1307F】Cow and Vacation(并查集+lca倍增)
description
solution
考虑将边拆分,边长 × 2 imes 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 " ); 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 " ); else printf( "NO " ); } } return 0; }