【CF1307F】Cow and Vacation(并查集+lca倍增)

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;
}

猜你喜欢

转载自blog.csdn.net/Emm_Titan/article/details/114111203