CF - 620(div2) -- E. 1-Trees and Queries【LCA + 思维】

题意

给出一棵树,询问在增加一条边的情况下,是否存在a->b走过的边权和正好为k(可重复经过某边)。

思路

ps:漏了两个判断条件,真惨。
首先可以重复经过某些顶点和边,假设a到b的距离是dis,那么dis + 2, dis + 4,
dis + 6......这些都是满足的a到达b,现在只需要判断奇偶性。如果dis是奇数,那么k
必须是大于dis的奇数才行;偶数同理。a到b有三条路径d,
a -> b,
a -> x - > y - > b,  
a- > y - > x -> b.
然后记录dis与k的奇偶相同且最小的距离,判断是否小于等于k即可。

时间复杂度:O(m * logn)

AC代码

#include
#include
#include
#include
#include
using namespace std;
#define IOS ios::sync_with_stdio(false)
const int maxn = 2e5 + 100;
const int inf = 0x3f3f3f3f;
struct Edge{
	int to, next, w;
}edge[maxn];
int dis[maxn], fa[21][maxn], head[maxn], deep[maxn], cnt;
void init(){
	memset(dis, 0, sizeof(dis));
	memset(fa, 0, sizeof(fa));
	memset(head, -1, sizeof(head));
	memset(deep, 0, sizeof(deep));
	cnt = 0;
}
void add(int u, int v, int w){
	edge[cnt].to = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt++;
}
void dfs(int u, int fno){
	for (int i = 1; i <=20; ++i){
		fa[i][u] = fa[i - 1][fa[i - 1][u]];
	}
	for (int i = head[u]; ~i; i = edge[i].next){
		int v = edge[i].to;
		if (v == fno)	continue;
		dis[v] = dis[u] + edge[i].w;
		fa[0][v] = u;
		deep[v] = deep[u] + 1;
		dfs(v, u);
	}
}
int LCA(int x, int y){
	if (deep[x] < deep[y]){
		swap(x, y);
	}
	for (int i = 20; i >= 0; --i){
		if (deep[x] -deep[y] >> i){
			x = fa[i][x];
		}
	}
	if (x == y)		return x;
	for (int i = 20; i >= 0; --i){
		if (fa[i][x] != fa[i][y]){
			x = fa[i][x];
			y = fa[i][y];
		}
	}
	return fa[0][x];
}
int distance(int x, int y){
	return dis[x] + dis[y] - 2 * dis[LCA(x, y)];
}
void solve(){
	int n, u, v;
	scanf("%d", &n);
	init();
	for (int i = 1; i < n; ++i){
		scanf("%d%d", &u, &v);
		add(u, v, 1);
		add(v, u, 1);
	}
	dfs(1, 0);
	int m, x, y, a, b, k;
	scanf("%d", &m);
	while (m--){
		scanf("%d%d%d%d%d", &x, &y, &a, &b, &k);
		int disab1 = distance(a, b);
		int disab2 = distance(a, x) + distance(b, y) + 1;
		int disab3 = distance(a, y) + distance(b, x) + 1;
		int flag = inf;
		//记录a到b的距离,并且判断disab和k的奇偶相同,如果相同记录ab最短路径是否小于等于k即可。 
		if (disab1 % 2 == k % 2){
			flag = min(flag, disab1);
		}
		if (disab2 % 2 == k % 2){
			flag = min(flag, disab2);
		}
		if (disab3 % 2 == k % 2){
			flag = min(flag, disab3);
		}
		if (flag <= k){
			puts("YES");
		} else {
			puts("NO");
		}
	}
}
int main(){
	solve();
	return 0;
}

你可能感兴趣的:(#,最近公共祖先(LCA),#,思维题)