codeforces #629 E-Tree Queries

  • 题意:给一个以1为根节点树,m次询问,每次选k个节点,问是否存在一个节点u,在1~u的路径上所有这k个点到这条路径的距离都小于等于1。
  • 题解:d[]记录每个点到根节点的距离,这个u一定是k个点中d[]最大的那个点。然后判断其他点满足条件吗。判断方法就是看d[a[i]] - d[lca(u, a[i])] 是否都小于 1。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 2e5 + 105;
const int mod = 1e9 + 7;
const double Pi = 3.1415926;
const ll INF = 0x3f3f3f3f;

int n, m, t, k, flag = 0;
int head[N], cnt = 0;
int d[N], a[N], f[N][20];


struct node{
	int to;
	int nxt;
}edge[4 * N];
queue<int>q;

inline void add(int x, int y){
	edge[cnt].to = y;
	edge[cnt].nxt = head[x];
	head[x] = cnt ++;
}

void bfs(){
	q.push(1);
	d[1] = 1;
	while(!q.empty()){
		int x = q.front();
		q.pop();
		for(int i  = head[x]; i != -1; i = edge[i].nxt){
			int y = edge[i].to;
			if(d[y]) continue;
			d[y] = d[x] + 1;
			f[y][0] = x;
			for(int j = 1; j <= t; ++ j)
				f[y][j] = f[f[y][j - 1]][j - 1];
			q.push(y);
		}
	}
}

int LCA(int x, int y){
	if(d[x] > d[y]) swap(x, y);
	for(int i = t; i >= 0; -- i)
		if(d[f[y][i]] >= d[x]) y = f[y][i];
	if(x == y) return x;
	for(int i = t; i >= 0; -- i)
		if(f[x][i] != f[y][i]) 
			x = f[x][i], y = f[y][i];
	return f[x][0];
}



int main()
{
	memset(head, -1, sizeof(head));
	scanf("%d%d",&n,&m);
	t = (int)(log(n) / log(2)) + 1;
	for(int i = 1; i < n; ++ i){
		int x, y;
		scanf("%d%d",&x,&y);
		add(x, y);
		add(y, x);
	}
	bfs();
	
	while(m --){
		scanf("%d",&k);
		flag = 0;
		int base = 0, maxx = 0;
		for(int i = 1; i <= k; ++ i){
			scanf("%d",&a[i]);
			if(d[a[i]] > maxx){
				maxx = d[a[i]];
				base = a[i];
			}
		}
		for(int i = 1; i <= k; ++ i){
			if(base == a[i]) continue;
			int lca = LCA(base, a[i]);
			if(d[a[i]] - d[lca] > 1) flag = 1;
		}
		if(!flag) printf("YES
");
		else printf("NO
");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/A-sc/p/12726243.html