[题解]SP913:QTREE2

版权声明:Fashion Education https://blog.csdn.net/ModestCoder_/article/details/88980770

@LuoGu
本题两个询问,dist询问是lca基本做法吧
主要是kth询问

其实也是lca,跟树剖一点关系也没有~
先求一遍lca,可以知道kth的点在s->lca(s,t)上还是lca(s,t)->t上
之后再倍增跑一边即可~

Code:

#include <bits/stdc++.h>
#define maxn 10010
using namespace std;
struct Edge{
	int to, len, next;
}edge[maxn << 1];
int head[maxn << 1], fa[maxn][30], d[maxn], dis[maxn], num, n;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

void add_edge(int x, int y, int z){ edge[++num].to = y; edge[num].len = z; edge[num].next = head[x]; head[x] = num; }

void build(int u){
	for (int i = 0; fa[u][i]; ++i) fa[u][i + 1] = fa[fa[u][i]][i];
	for (int i = head[u]; i; i = edge[i].next){
		int v = edge[i].to;
		if (v != fa[u][0]){
			d[v] = d[u] + 1, dis[v] = dis[u] + edge[i].len, fa[v][0] = u;
			build(v);
		}
	}
}

int lca(int u, int v){
	if (d[u] < d[v]) swap(u, v);
	for (int i = 20; i >= 0; --i) if (d[v] + (1 << i) <= d[u]) u = fa[u][i];
	if (u == v) return u;
	for (int i = 20; i >= 0; --i) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}

int query(int u, int v, int k){
	int x = lca(u, v);
	if (k <= d[u] - d[x] + 1){
		--k;
		for (int i = 20; i >= 0; --i) if (k >= (1 << i)) k -= (1 << i), u = fa[u][i];
		return u;
	} else{
		k = d[u] + d[v] - (d[x] << 1) + 1 - k;
		for (int i = 20; i >= 0; --i) if (k >= (1 << i)) k -= (1 << i), v = fa[v][i];
		return v;
	}
}

int main(){
	int M = read();
	while (M--){
		num = 0;
		memset(head, 0, sizeof(head));
		memset(edge, 0, sizeof(edge));
		memset(d, 0, sizeof(d));
		memset(dis, 0, sizeof(dis));
		memset(fa, 0, sizeof(fa));
		n = read();
		for (int i = 1; i < n; ++i){
			int x = read(), y = read(), z = read();
			add_edge(x, y, z); add_edge(y, x, z);
		}
		build(1);
		while (1){
			char c = getchar();
			for (; c != 'I' && c != 'T' && c != 'O'; c = getchar());
			if (c == 'O') break;
			if (c == 'I'){
				int x = read(), y = read();
				printf("%d\n", dis[x] + dis[y] - (dis[lca(x, y)] << 1));
			} else{
				int x = read(), y = read(), z = read();
				printf("%d\n", query(x, y, z));
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/88980770