LCA转RMQ学习、

学习博客:传送门

LCA和RMQ的转化问题:传送门

之前一直不理解dp[i][j]代表的含义,实际上dp[i][j]就是文章中提到的pos数组,因为比较的时候直接比较的是深度,是利用位置取比较深度,存储的依然是位置

写了个模板题

HDU 2586

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <map>
#include <set>
#include <vector>
#include <utility>
#include <queue>
#include <stack>
#include <string>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int qq = 2e5 + 10;
const int MOD = 1e9 + 7;
int in[qq], dep[qq << 1], R[qq << 1], dp[qq << 1][15], Time;
int n, m;
vector<int> vt[qq], d[qq];
void Init() {
	Time = 0;
	for(int i = 0; i <= n; ++i) {
		vt[i].clear(), d[i].clear();
	}
}
void RmqInit() {
	for(int i = 1; i <= Time; ++i) {
		dp[i][0] = i;
	}
	for(int j = 1; (1 << j) <= Time; ++j) {
		for(int i = 1; i + (1 << j) - 1 <= Time; ++i) {
			int a = dp[i][j - 1];
			int b = dp[i + (1 << (j - 1))][j - 1];
			if(dep[a] <= dep[b]) {
				dp[i][j] = a;
			} else {
				dp[i][j] = b;
			}
		}
	}
}
void Dfs(int u, int dis, int fa) {
	in[u] = ++Time;
	R[Time] = u;
	dep[Time] = dis;
	for(int i = 0; i < (int)vt[u].size(); ++i) {
		int v = vt[u][i];
		if(v == fa)	continue;
		Dfs(v, dis + d[u][i], u);
		R[++Time] = u;
		dep[Time] = dis;
	}
}
int Rmq(int l, int r) {
	int k = 0;
	while((1 << (k + 1)) <= r - l + 1)	k++;
	int a = dp[l][k], b = dp[r - (1 << k) + 1][k];
	if(dep[a] <= dep[b])	return R[a];
	return R[b];
}
int Lca(int u, int v) {
	int x = in[u], y = in[v];
	if(x > y) swap(x, y);
	return Rmq(x, y);
}
int Dis(int u, int v) {
	return dep[in[u]] + dep[in[v]] - 2 * dep[in[Lca(u, v)]];
}

int Solve(int a, int b) {
	return Dis(a, b);
}

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		scanf("%d%d", &n ,&m);
		Init();
		for(int x, y, z, i = 2; i <= n; ++i) {
			scanf("%d%d%d", &x, &y, &z);
			vt[x].pb(y), d[x].pb(z);
			vt[y].pb(x), d[y].pb(z);
		}
		Dfs(1, 0, -1);
		RmqInit();
		while(m--) {
			int u, v;	scanf("%d%d", &u, &v);
			printf("%d\n", Solve(u, v));
		}
	}
	return 0;
}



Codeforces 832D

题意:给出一棵树,然后给你三个点,你可以选择其中两个点为起点,剩下点是终点,求两条路径相交最多有多少个点

思路:分析可以发现答案就是( dis(s, t) + dis(f, t) - dis(s, t) ) / 2 + 1

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <map>
#include <set>
#include <vector>
#include <utility>
#include <queue>
#include <stack>
#include <string>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int qq = 2e5 + 10;
const int MOD = 1e9 + 7;
int in[qq], dep[qq << 2], R[qq << 2], dp[qq << 2][20], Time;
int n, m;
vector<int> vt[qq];
void Init() {
	Time = 0;
}
void RmqInit() {
	for(int i = 1; i <= Time; ++i) {
		dp[i][0] = i;
	}
	for(int j = 1; (1 << j) <= Time; ++j) {
		for(int i = 1; i + (1 << j) - 1 <= Time; ++i) {
			int a = dp[i][j - 1];
			int b = dp[i + (1 << (j - 1))][j - 1];
			if(dep[a] <= dep[b]) {
				dp[i][j] = a;
			} else {
				dp[i][j] = b;
			}
		}
	}
}
void Dfs(int u, int dis, int fa) {
	in[u] = ++Time;
	R[Time] = u;
	dep[Time] = dis;
//	printf("%d %d\n", R[Time], dep[Time]);
	for(int i = 0; i < (int)vt[u].size(); ++i) {
		int v = vt[u][i];
		if(v == fa)	continue;
		Dfs(v, dis + 1, u);
		R[++Time] = u;
		dep[Time] = dis;
//		printf("%d %d\n", R[Time], dep[Time]);
	}
}
int Rmq(int l, int r) {
	int k = 0;
	while((1 << (k + 1)) <= r - l + 1)	k++;
	int a = dp[l][k], b = dp[r - (1 << k) + 1][k];
//	printf("%d %d\n", a, b);
	if(dep[a] <= dep[b])	return R[a];
	return R[b];
}
int Lca(int u, int v) {
	if(u == v)	return u;
	int x = in[u], y = in[v];
	if(x > y) swap(x, y);
	return Rmq(x, y);
}
int Dis(int u, int v) {
	return dep[in[u]] + dep[in[v]] - 2 * dep[in[Lca(u, v)]];
}

int Solve(int a, int b, int c) {
	int x = Dis(b, a) + Dis(c, a) - Dis(b, c);
	int y = Dis(a, b) + Dis(c, b) - Dis(a, c);
	int z = Dis(a, c) + Dis(b, c) - Dis(a, b);
	return max({x, y, z});
}

int main(){
	scanf("%d%d", &n ,&m);
	Init();
	for(int x, i = 2; i <= n; ++i) {
		scanf("%d", &x);
		vt[x].pb(i);
		vt[i].pb(x);
	}
	Dfs(1, 0, -1);
	RmqInit();
	while(m--) {
		int u, v, s;	scanf("%d%d%d", &u, &v, &s);
//		printf("%d %d %d\n", Dis(u, v), Dis(u, s), Dis(v, s));
		printf("%d\n", Solve(u, v, s) / 2 + 1);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值