CDOJ 92 Journey(LCA&RMQ)
题目连接:http://acm.uestc.edu.cn/#/problem/show/92
题意:给定一棵树,最后给加一条边,给定Q次查询,每次查询加上最后一条边之后是否比不加这条边要近,如果近的话,输出近多少,否则输出0
思路:没加最后一条边之前两点之间的距离是dis(u) + dis(v) - 2*dis(lca(u, v)); 加上之后就是必须要经过这两个点。(假设最后添加的一条边的端点为x和y,权值为w)min(dis(u, x) + dis(v, y) + w, dis(u, y) + dis(v, x) + w)
代码如下:
/************************************************************************* > File Name: 4.cpp > Author: Howe_Young > Mail: 1013410795@qq.com > Created Time: 2015年10月08日 星期四 19时53分38秒 ************************************************************************/ #include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e5 + 20; struct Edge { int to, next, w; }edge[maxn<<1]; int tot, head[maxn]; int cnt; int Euler[maxn<<1]; int R[maxn]; int dis[maxn<<1]; int dep[maxn<<1]; int dp[maxn<<1][20]; void init() { cnt = 0; tot = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int w) { edge[tot].to = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot++; } void dfs(int u, int fa, int depth, int dist) { Euler[++cnt] = u; R[u] = cnt; dep[cnt] = depth; dis[cnt] = dist; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (v == fa) continue; dfs(v, u, depth + 1, dist + edge[i].w); Euler[++cnt] = u; dep[cnt] = depth; dis[cnt] = dist; } } void RMQ(int n) { for (int i = 1; i <= n; i++) dp[i][0] = i; int m = log2(n); for (int j = 1; j <= m; j++) for (int i = 1; i + (1 << j) - 1 <= n; i++) dp[i][j] = dep[dp[i][j - 1]] < dep[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]; } int getLCA(int u, int v) { if (u == v) return v; int l = R[u], r = R[v]; if (l > r) swap(l, r); int k = log2(r - l + 1); int lca = dep[dp[l][k]] < dep[dp[r - (1 << k) + 1][k]] ? dp[l][k] : dp[r - (1 << k) + 1][k]; return Euler[lca]; } int getdist(int u, int v) { if (u == v) return 0; int l = R[u], r = R[v]; int lca = getLCA(u, v); return dis[l] + dis[r] - 2 * dis[R[lca]]; } int main() { int T, kase = 0; scanf("%d", &T); while (T--) { init(); int n, Q; int u, v, w; scanf("%d %d", &n, &Q); for (int i = 1; i < n; i++) { scanf("%d %d %d", &u, &v, &w); addedge(u, v, w); addedge(v, u, w); } scanf("%d %d %d", &u, &v, &w); dfs(1, 0, 1, 0); RMQ(cnt); printf("Case #%d:\n", ++kase); while (Q--) { int a, b; scanf("%d %d", &a, &b); int dis1 = getdist(a, b); int dis2 = min(getdist(a, u) + getdist(v, b) + w, getdist(a, v) + getdist(u, b) + w); if (dis1 > dis2) printf("%d\n", dis1 - dis2); else printf("0\n"); } } return 0; }