HDOJ2586 How far away ?LCA

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=2586

分析

数据规模较大,用Tarjan求LCA的方法来求树上两点间路径长度;

d i s ( x , y ) = d e p t h [ x ] + d e p t h [ y ] − 2 ∗ d e p t h [ l c a ( x , y ) ] dis(x, y) = depth[x] + depth[y] - 2 * depth[lca(x, y)] dis(x,y)=depth[x]+depth[y]2depth[lca(x,y)]

注意数组要开够,否则会报TLE???

AC代码

#include <cstdio>
#include <cstring>

inline int read() {
	int num = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9')
		num = num * 10 + c - '0', c = getchar();
	return num;
}

const int maxn = 4e4 + 5, maxm = 205;

int head[maxn], eid, point[maxn], qid;

struct Edge {
	int v, w, next;
} edge[2 * maxn];

inline void insert(int u, int v, int w) {
	edge[++eid].v = v;
	edge[eid].w = w;
	edge[eid].next = head[u];
	head[u] = eid;
}

struct Query {
	int id, x, next;
} query[2 * maxm];

inline void add(int id, int x, int y) {
	query[++qid].id = id;
	query[qid].x = y;
	query[qid].next = point[x];
	point[x] = qid;
}

int f[maxn], flag[maxn], d[maxn], ans[maxm];

int find(int x) {
	if (x == f[x]) return x;
	return f[x] = find(f[x]);
}

void tarjan(int u, int fa) {
	flag[u] = 1;
	for (int p = head[u]; p; p = edge[p].next) {
		int v = edge[p].v, w = edge[p].w;
		if (v == fa) continue;
		d[v] = d[u] + w;
		tarjan(v, u);
		f[v] = u;
	}
	for (int p = point[u]; p; p = query[p].next) {
		int id = query[p].id, x = query[p].x;
		if (flag[x] == 2) ans[id] = d[u] + d[x] - 2 * d[find(x)];
	}
	flag[u] = 2;
}

int main() {
	int t = read();
	while (t--) {
		memset(head, 0, sizeof(head));
		memset(point, 0, sizeof(point));
		memset(flag, 0, sizeof(flag));
		eid = qid = 0;
		int n = read(), m = read();
		for (int i = 1; i < n; ++i) {
			int u = read(), v = read(), w = read();
			insert(u, v, w), insert(v, u, w);
		}
		for (int i = 1; i <= m; ++i) {
			int x = read(), y = read();
			add(i, x, y), add(i, y, x);
		}
		for (int i = 1; i <= n; ++i) f[i] = i;
		tarjan(1, 0);
		for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值