Query on a tree II 倍增LCA

Posted zxyqzy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Query on a tree II 倍增LCA相关的知识,希望对你有一定的参考价值。

You are given a tree (an undirected acyclic connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. Each edge has an integer value assigned to it, representing its length.

We will ask you to perfrom some instructions of the following form:

  • DIST a b : ask for the distance between node a and node b
    or
  • KTH a b k : ask for the k-th node on the path from node a to node b

Example:
N = 6
1 2 1 // edge connects node 1 and node 2 has cost 1
2 4 1
2 5 2
1 3 1
3 6 2

Path from node 4 to node 6 is 4 -> 2 -> 1 -> 3 -> 6
DIST 4 6 : answer is 5 (1 + 1 + 1 + 2 = 5)
KTH 4 6 4 : answer is 3 (the 4-th node on the path from node 4 to node 6 is 3)

Input

The first line of input contains an integer t, the number of test cases (t <= 25). t test cases follow.

For each test case:

  • In the first line there is an integer N (N <= 10000)
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 100000)
  • The next lines contain instructions "DIST a b" or "KTH a b k"
  • The end of each test case is signified by the string "DONE".

There is one blank line between successive tests.

Output

For each "DIST" or "KTH" operation, write one integer representing its result.

Print one blank line after each test.

Example

Input:
1

6
1 2 1
2 4 1
2 5 2
1 3 1
3 6 2
DIST 4 6
KTH 4 6 4
DONE

Output:
5
3

看到树上两点距离很容易想到LCA,
对于第K个点我们同样可以倍增解决;
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<bitset>
#include<ctime>
#include<time.h>
#include<deque>
#include<stack>
#include<functional>
#include<sstream>
//#include<cctype>
//#pragma GCC optimize(2)
using namespace std;
#define maxn 200005
#define inf 0x7fffffff
//#define INF 1e18
#define rdint(x) scanf("%d",&x)
#define rdllt(x) scanf("%lld",&x)
#define rdult(x) scanf("%lu",&x)
#define rdlf(x) scanf("%lf",&x)
#define rdstr(x) scanf("%s",x)
#define mclr(x,a) memset((x),a,sizeof(x))
typedef long long  ll;
typedef unsigned long long ull;
typedef unsigned int U;
#define ms(x) memset((x),0,sizeof(x))
const long long int mod = 9999973;
#define Mod 1000000000
#define sq(x) (x)*(x)
#define eps 1e-5
typedef pair<int, int> pii;
#define pi acos(-1.0)
//const int N = 1005;
#define REP(i,n) for(int i=0;i<(n);i++)
typedef pair<int, int> pii;

inline int rd() {
	int x = 0;
	char c = getchar();
	bool f = false;
	while (!isdigit(c)) {
		if (c == ‘-‘) f = true;
		c = getchar();
	}
	while (isdigit(c)) {
		x = (x << 1) + (x << 3) + (c ^ 48);
		c = getchar();
	}
	return f ? -x : x;
}


ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a%b);
}
int sqr(int x) { return x * x; }



/*ll ans;
ll exgcd(ll a, ll b, ll &x, ll &y) {
	if (!b) {
		x = 1; y = 0; return a;
	}
	ans = exgcd(b, a%b, x, y);
	ll t = x; x = y; y = t - a / b * y;
	return ans;
}
*/

struct node {
	int u, v, w, nxt;
}e[maxn];
int head[maxn];
int tot;
int n;
int dis[maxn], dep[maxn];
int fa[maxn][20];
void init() {
	ms(e); ms(head); tot = 0; ms(dis); ms(dep);
	ms(fa);
}

void addedge(int u, int v, int w) {
	e[++tot].u = u; e[tot].v = v; e[tot].nxt = head[u]; e[tot].w = w;
	head[u] = tot;
}


void dfs(int rt) {
	for (int i = 1; i <= (int)log(n) / log(2) + 1; i++)
		fa[rt][i] = fa[fa[rt][i - 1]][i - 1];
	for (int i = head[rt]; i; i = e[i].nxt) {
		int v = e[i].v;
		if (v == fa[rt][0])continue;
		fa[v][0] = rt; dep[v] = dep[rt] + 1;
		dis[v] = dis[rt] + e[i].w;
		dfs(v);
	}
}

int LCA(int x, int y) {
	if (dep[x] > dep[y])swap(x, y);
	for (int i = (int)log(n) / log(2) + 1; i >= 0; i--) {
		if (dep[fa[y][i]] >= dep[x])y = fa[y][i];
	}
	if (x == y)return x;
	for (int i = (int)log(n) / log(2) + 1; i >= 0; i--) {
		if (fa[x][i] != fa[y][i]) {
			x = fa[x][i]; y = fa[y][i];
		}
	}
	return fa[x][0];
}

int main()
{
//	ios::sync_with_stdio(0);
	int T = rd();
	while (T--) {
		n = rd();
		init();
		for (int i = 1; i < n; i++) {
			int u = rd(), v = rd(), w = rd();
			addedge(u, v, w); addedge(v, u, w);
		}
		dfs(1);
		char op[20];
		while (rdstr(op) != EOF && op[1] != ‘O‘) {
			if (op[1] == ‘I‘) {
				int u = rd(), v = rd();
			//	cout << dis[u] << ‘ ‘ << dis[v] << ‘ ‘ << dis[LCA(u, v)] << endl;
				printf("%d
", dis[u] + dis[v] - 2 * dis[LCA(u, v)]);
			}
			else {
				int u = rd(), v = rd(), k = rd();
				int root = LCA(u, v);
				int ans;
				if (dep[u] - dep[root] + 1 >= k) {
					ans = dep[u] - k + 1;
					int i;
					for (i = 0; (1 << i) <= dep[u]; i++); i--;
					for (int j = i; j >= 0; j--) {
						if (dep[u] - (1 << j) >= ans)u = fa[u][j];
					}
					printf("%d
", u);
				}
				else {
					ans = dep[root] + k - (dep[u] - dep[root] + 1);
					int i;
					for (i = 0; (1 << i) <= dep[v]; i++); i--;
					for (int j = i; j >= 0; j--) {
						if (dep[v] - (1 << j) >= ans)v = fa[v][j];
					}
					printf("%d
", v);
				}
			}
		}
	}
	return 0;
}

 















以上是关于Query on a tree II 倍增LCA的主要内容,如果未能解决你的问题,请参考以下文章

Query on a tree II LCA题 [SPOJ-QTREE2]

SPOJ QTREE2QTREE2 - Query on a tree II(LCA)

LCA SP913 QTREE2 - Query on a tree II

SP913 QTREE2 - Query on a tree II

SPOJ QTREE2 Query on a tree II

SPOJ10707 COT2 - Count on a tree II 树上莫队