F. Journey
题目链接:这儿
题目大意:给一棵树T,每条边都有一个权值,然后又一条新增边,多次询问:从点x到点y在T上走的最短距离,在加上那条新增边之后,最短距离可以减少多少。
思路:任意确定一个根root,DFS计算每个点到根的距离dis[],然后每两点间的最短距离为 dis[x]+dis[y]-2*dis[LCA(x,y)]。若新加入一条边u--v,那么如果我们必须经过u--v,那么从x到y的最短距离就为 dis(x,u)+dis(u,v)+dis(v,y)或dis(x,v)+dis(v,u)+dis(u,y)。这样在线处理答案就行。
PS:至于求LCA的方法可以参考2007年郭华阳的论文《RMQ&LCA问题》,RMQ可以用ST算法,至于那个O(n)的±1RMQ有空再写把……
AC Code:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int MAXN = 300010; 7 const int MAXM = MAXN * 2; 8 9 int head[MAXN]; 10 int next[MAXM], to[MAXM], cost[MAXM]; 11 int ecnt, root; 12 13 void init() { 14 ecnt = 1; 15 memset(head, 0, sizeof(head)); 16 } 17 18 void addEdge(int u, int v, int c) { 19 to[ecnt] = v; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++; 20 to[ecnt] = u; cost[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++; 21 } 22 23 int dis[MAXN]; 24 25 void dfs(int f, int u, int di) { 26 dis[u] = di; 27 for(int p = head[u]; p; p = next[p]) { 28 if(to[p] == f) continue; 29 dfs(u, to[p], di + cost[p]); 30 } 31 } 32 33 int RMQ[2*MAXN], mm[2*MAXN], best[20][2*MAXN]; 34 35 void initRMQ(int n) { 36 int i, j, a, b; 37 mm[0] = -1; 38 for(i = 1; i <= n; ++i) 39 mm[i] = ((i&(i-1)) == 0) ? mm[i-1] + 1 : mm[i-1]; 40 for(i = 1; i <= n; ++i) best[0][i] = i; 41 for(i = 1; i <= mm[n]; ++i) { 42 for(j = 1; j <= n + 1 - (1 << i); ++j) { 43 a = best[i - 1][j]; 44 b = best[i - 1][j + (1 << (i - 1))]; 45 if(RMQ[a] < RMQ[b]) best[i][j] = a; 46 else best[i][j] = b; 47 } 48 } 49 } 50 51 int askRMQ(int a,int b) { 52 int t; 53 t = mm[b - a + 1]; b -= (1 << t)-1; 54 a = best[t][a]; b = best[t][b]; 55 return RMQ[a] < RMQ[b] ? a : b; 56 } 57 58 int dfs_clock, num[2*MAXN], pos[MAXN];//LCA 59 60 void dfs_LCA(int f, int u, int dep) { 61 pos[u] = ++dfs_clock; 62 RMQ[dfs_clock] = dep; num[dfs_clock] = u; 63 for(int p = head[u]; p; p = next[p]) { 64 if(to[p] == f) continue; 65 dfs_LCA(u, to[p], dep + 1); 66 ++dfs_clock; 67 RMQ[dfs_clock] = dep; num[dfs_clock] = u; 68 } 69 } 70 71 int LCA(int u, int v) { 72 if(pos[u] > pos[v]) swap(u, v); 73 return num[askRMQ(pos[u], pos[v])]; 74 } 75 76 void initLCA(int n) { 77 dfs_clock = 0; 78 dfs_LCA(0, root, 0); 79 initRMQ(dfs_clock); 80 } 81 82 inline int _abs(const int &x) { 83 return x > 0 ? x : -x; 84 } 85 86 int mindis(int x, int y) { 87 return dis[x] + dis[y] - 2 * dis[LCA(x, y)]; 88 } 89 90 int main() { 91 int T, n, Q; 92 int x, y, z, p; 93 int u, v; 94 scanf("%d", &T); 95 for(int t = 1; t <= T; ++t) { 96 printf("Case #%d:\n", t); 97 scanf("%d%d", &n, &Q); 98 init(); 99 for(int i = 0; i < n - 1; ++i) { 100 scanf("%d%d%d", &x, &y, &z); 101 addEdge(x, y, z); 102 } 103 scanf("%d%d%d", &x, &y, &z); 104 root = x; 105 dis[root] = 0; 106 for(p = head[root]; p; p = next[p]) dfs(root, to[p], cost[p]); 107 initLCA(n); 108 while(Q--) { 109 scanf("%d%d", &u, &v); 110 int ans1 = mindis(u, v); 111 int ans2 = min(mindis(u, x) + mindis(y, v), mindis(u, y) + mindis(x, v)) + z; 112 if(ans1 > ans2) printf("%d\n", ans1 - ans2); 113 else printf("0\n"); 114 } 115 } 116 }
By Oyking