【题解】How far away ? HDU - 2586 ⭐⭐⭐ 【LCA】

How far away ? HDU - 2586

勇气小镇是一个有着n个房屋的小镇,为什么把它叫做勇气小镇呢,这个故事就要从勇气小镇成立的那天说起了,
修建小镇的时候,为了让小镇有特色,镇长特地只修了n-1条路,并且规定说,所有在勇气小镇的村民,每一次出门必须规划好路线,
路线必须满足在到达终点之前绝对不走回头路。每个人都要这样,不然那个人就不配在小镇生活下去,因为他没有这个勇气。
事实上,这并不能算一项挑战,因为n-1条路已经连通了每户人家,不回头地从起点到终点,只是一个时间上的问题。
由于小镇上的福利特别好,所以小懒入住了这个小镇,他规划了m次的行程,每次从L房屋到R房屋,他想问你他每次从L房屋到R房屋最少能走多少路。

Input

输入的第一行是一个整数t,表示有t组数据
每组数据第一行是n,m两个数字,分别表示小镇上房屋的个数,和小懒计划的行程的数量。
之后第2行到第n行,每行三个整数a,b,c表示,a房屋与b房屋之间连接着一条距离为c的小路。
第n+1行到第n+m行,每行两个整数,L,R,代表一次小懒的询问,也就是询问小懒从L房屋走到R房屋所走的最近距离为多少。

Output

对于每组测试数据输出m行,每行一个整数,代表小懒从询问的L到R需要走的最近的距离

Examples

Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100

Hint

t<=10
2<=n<=40000
1<=m<=200
1<=a<=n
1<=b<=n
1<=c<=40000
1<=L<=n
1<=R<=n




题意:

对于一棵树做离线查询, 输出2点间的距离

题解:

使用Tarjan离线查询即可, 需要做一点修改
dis[i]表示根节点(假设1号点为根) 第 i 点的距离, 在Tarjan中更新距离和lca(u, v)
对于查询u, v两点的距离, 输出dis[u]+dis[v]-2*dis[lca(u, v)]即可

经验小结:


#include
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef  long long LL;
const int inf = 1 << 30;
const int MAXN = 4e4+10;

int par[MAXN];
int findr(int u) {
    if(par[u] == u) return u;
    return par[u] = findr(par[u]);
}
void unite(int u, int v) {
    u = findr(u);
    v = findr(v);
    if(u != v) par[v] = u;
}
bool vis[MAXN];
struct G {
    int to, next, w;
} G[MAXN * 2];
int head[MAXN], ecnt;
void addEdge(int u, int v, int w) {
    G[ecnt].to = v;
    G[ecnt].w= w;
    G[ecnt].next = head[u];
    head[u] = ecnt++;
}
struct Query {
    int q, next;
    int id;
} query[MAXN * 2];
int h[MAXN], qcnt, Q;
void addQuery(int u, int v, int id) {
    query[qcnt].q = v;
    query[qcnt].next = h[u];
    query[qcnt].id = id;
    h[u] = qcnt++;
}
int lca[MAXN]; //询问边对应的最近公共祖先
int dis[MAXN];  //根节点到每个点的距离
int l[MAXN], r[MAXN];
void LCA(int u) {
    vis[u] = true;
    for(int i = head[u]; i != -1; i = G[i].next) {
        int v = G[i].to;
        if(vis[v]) continue;
        dis[v] = dis[u] + G[i].w;
        LCA(v);
        unite(u, v);
    }
    for(int i = h[u]; i != -1; i = query[i].next){
        int v = query[i].q;
        if(vis[v])
            lca[query[i].id] = findr(v);
    }
}
void init(int N) {
    for(int i = 0; i <= N; ++i) par[i] = i;
    ecnt = qcnt = 0;
    memset(head, -1, sizeof(head));
    memset(h, -1, sizeof(h));
    memset(vis, 0, sizeof(vis));
}
int main() {
    int T, u, v, w, N, M;
    cin >> T;
    while(T--){
        cin >> N >> M;
        init(N);
        for(int i = 1; i < N; ++i){
            cin >> u >> v >> w;
            addEdge(u, v, w);
            addEdge(v, u, w);
        }
        for(int i = 1; i <= M; ++i){
            cin >> l[i] >> r[i];
            addQuery(l[i], r[i], i);
            addQuery(r[i], l[i], i);
        }
        dis[1] = 0;
        LCA(1);
        for(int i = 1; i <= M; ++i)
            cout << dis[l[i]]+dis[r[i]]-2*dis[lca[i]] << endl;
    }
    return 0;
}

你可能感兴趣的:(图论)