HDU2586 - How far away?

2016/11/15

一道倍增 LCA 的裸题。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <bits/stdc++.h>
using namespace std;
const int ESIZ = 1E5;
typedef pair<int, int> PII;
struct tgno {
    int u, v, w;
    tgno *n;
} POOL[ESIZ]; int ppos;
tgno* Head[ESIZ];

void _add(int u, int v, int w) {
    POOL[ppos].u = u; POOL[ppos].v = v;
    POOL[ppos].w = w; POOL[ppos].n = Head[u];
    Head[u] = &POOL[ppos++];
}
void addEdge(int u, int v, int w) {
    _add(u, v, w); _add(v, u, w);
}
int N, M;

int vis[ESIZ];
int dep[ESIZ], pre[ESIZ][20], dis[ESIZ][20];
void dfs(int curr) {
    typedef tgno* It;
    for(It i=Head[curr];i;i=i->n) {
        if(!dep[i->v]) {
            dep[i->v] = dep[curr] + 1;
            pre[i->v][0] = curr;
            dis[i->v][0] = i->w;
            dfs(i->v);
        }
    }
}

void mkLCA(int R) {
    memset(vis, 0x00, sizeof(vis));
    memset(dep, 0x00, sizeof(dep));
    memset(dis, 0x3F, sizeof(dis)); dep[R]=1;
    dfs(R);
    
    for(int j=1;(1<<j)<=N;j++) {
        for(int i=1;i<=N;i++) {
            if(pre[i][j-1]) {
                pre[i][j] = pre[pre[i][j-1]][j-1];
                dis[i][j] = dis[i][j-1] + dis[pre[i][j-1]][j-1];
            }
        }
    }
}

// < LCA, Distance >
PII LCA(int A, int B) {
    int dd = 0, i, j, a = A, b = B;
    if(dep[a] < dep[b]) swap(a, b);
    for(i=0;(1<<i)<=dep[a];i++);
    i--;
    for(j=i;j>=0;j--)
        if(dep[a]-(1<<j)>=dep[b]) {
            dd += dis[a][j]; a = pre[a][j];
        }
    if(a == b) return PII(a, dd);
    for(j=i;j>=0;j--) {
        if(pre[a][j] && pre[a][j] != pre[b][j]) {
            dd += dis[a][j]; a = pre[a][j];
            dd += dis[b][j]; b = pre[b][j];
        }
    }
    return PII(pre[a][0], dd + dis[a][0] + dis[b][0]);
}

int main() {
    int T; cin >> T;
    while(T--) {
        memset(POOL, 0x00, sizeof(POOL));
        memset(Head, 0x00, sizeof(Head));
        cin >> N >> M;
        int u, v, w; int _ = N-1;
        for(int i=0;i<_;i++) {
            cin >> u >> v >> w; addEdge(u, v, w);
        }
        
        mkLCA(1);
        
        for(int i=0;i<M;i++) {
            cin >> u >> v;
            cout << LCA(u, v).second << endl;
        }
    }
}