UESTC 1717 Journey(DFS+LCA)(Sichuan State Programming Contest 2012)

Description

Bob has traveled to byteland, he find the N cities in byteland formed a tree structure, a tree structure is very special structure, there is exactly one path connecting each pair of nodes, and a tree with N nodes has N - 1 edges.

As a traveler, Bob wants to journey between those N cities, and he know the time each road will cost. he advises the king of byteland building a new road to save time, and then, a new road was built. Now Bob has Q journey plan, give you the start city and destination city, please tell Bob how many time is saved by add a road if he always choose the shortest path. Note that if it's better not journey from the new roads,
the answer is 0.

Input

First line of the input is a single integer T(1 <= T <= 20), indicating there are T test cases.

For each test case, the first will line contain two integers N(2 <= N <= 10^5) and Q(1 <= Q <= 10^5), indicating the number of cities in byteland and the journey plans. Then N line followed, each line will contain three integer x, y(1 <= x,y <= N) and z(1 <= z <= 1000) indicating there is a road cost z time connect the x-th city and the y-th city, the first N - 1 roads will form a tree structure, indicating the original roads, and the N-th line is the road built after Bob advised the king. Then Q line followed, each line will contain two integer x and y(1 <= x,y <= N), indicating there is a journey plan from the x-th city to y-th city.

Output

For each case, you should first output "Case #t:" in a single line, where t indicating the case number between 1 and T, then Q lines followed, the i-th line contains one integer indicating the time could saved in i-th journey plan.

 

题目大意:给一棵树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有空再写把……

 

  1 #include <cstdio>

  2 #include <cstring>

  3 #include <algorithm>

  4 using namespace std;

  5 

  6 const int MAXN = 100010;

  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 initMM() {

 36     mm[0] = -1;

 37     for(int i = 1; i <= MAXN * 2 - 1; ++i)

 38        mm[i] = ((i&(i-1)) == 0) ? mm[i-1] + 1 : mm[i-1];

 39 }

 40 

 41 void initRMQ(int n) {

 42     int i, j, a, b;

 43     for(i = 1; i <= n; ++i) best[0][i] = i;

 44     for(i = 1; i <= mm[n]; ++i) {

 45         for(j = 1; j <= n + 1 - (1 << i); ++j) {

 46           a = best[i - 1][j];

 47           b = best[i - 1][j + (1 << (i - 1))];

 48           if(RMQ[a] < RMQ[b]) best[i][j] = a;

 49           else best[i][j] = b;

 50         }

 51     }

 52 }

 53 

 54 int askRMQ(int a,int b) {

 55     int t;

 56     t = mm[b - a + 1]; b -= (1 << t)-1;

 57     a = best[t][a]; b = best[t][b];

 58     return RMQ[a] < RMQ[b] ? a : b;

 59 }

 60 

 61 int dfs_clock, num[2*MAXN], pos[MAXN];//LCA

 62 

 63 void dfs_LCA(int f, int u, int dep) {

 64     pos[u] = ++dfs_clock;

 65     RMQ[dfs_clock] = dep; num[dfs_clock] = u;

 66     for(int p = head[u]; p; p = next[p]) {

 67         if(to[p] == f) continue;

 68         dfs_LCA(u, to[p], dep + 1);

 69         ++dfs_clock;

 70         RMQ[dfs_clock] = dep; num[dfs_clock] = u;

 71     }

 72 }

 73 

 74 int LCA(int u, int v) {

 75     if(pos[u] > pos[v]) swap(u, v);

 76     return num[askRMQ(pos[u], pos[v])];

 77 }

 78 

 79 void initLCA(int n) {

 80     dfs_clock = 0;

 81     dfs_LCA(0, root, 0);

 82     initRMQ(dfs_clock);

 83 }

 84 

 85 int mindis(int x, int y) {

 86     return dis[x] + dis[y] - 2 * dis[LCA(x, y)];

 87 }

 88 

 89 int main() {

 90     int T, n, Q;

 91     int x, y, z, p;

 92     int u, v;

 93     initMM();

 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 }
View Code

 

 

  

你可能感兴趣的:(programming)