Sicily 1820. How far away? (LCA的RMQ算法)

图遍历与RMQ问题
本文介绍了一种使用DFS初始化并结合RMQ算法解决树上路径最小值问题的方法。通过对树进行DFS预处理,建立稀疏表,实现快速查询两点间路径上的最小边权值。


#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
#include <cstdlib>
using namespace std;
struct node {
    int l, v;
    node(int vv = 0, int ll = 0): l(ll), v(vv) { }
};
vector<node> graph[10010];
int e[20010], nodes[40010], r[10010], dp[100010][20], visited[10010];
int pow2[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576};
int len;
void init_dfs(int x, int d)
{
    visited[x] = true;
    e[len] = d;
    nodes[len] = x;
    r[x] = len;
    len++;
    for (int i = 0; i < graph[x].size(); i++) {
        if (visited[graph[x][i].v]) continue;
       init_dfs(graph[x][i].v, d + graph[x][i].l);
       e[len] = d;
       nodes[len] = x;
       len++;
    }
}
void rmq(int qi, int qj, int& d)
{
    int len = log(qj - qi + 1.0) / log(2.0);
    if (dp[qi][len] < dp[qj - pow2[len] + 1][len]) {
       d = dp[qi][len];
    } else{
       d = dp[qj - pow2[len] + 1][len];
    }
}
int main()
{
    int n, li, q, ai, bi, ci, t, m, d;
    node temp;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &q);
       len = 0;
       for (int i = 0; i < n; i++)
           graph[i].clear();
       for (int i = 0; i < n - 1; i++) {
           scanf("%d%d%d", &ai, &bi, &ci);
           ai--, bi--;
           graph[ai].push_back(node(bi, ci));
           graph[bi].push_back(node(ai, ci));
       }
       memset(visited, 0, sizeof(visited));
       init_dfs(0, 0);
       memset(dp, 0, sizeof(dp));
       for (int i = 0; i < len; i++) 
           dp[i][0] = e[i];
       
       for (int j = 1; 1<<j <= len; j++)
           for (int i = 0; i+(1<<j)-1 < len; i++) {
              if (dp[i][j-1] < dp[i+pow2[j-1]][j-1]) 
                  dp[i][j] = dp[i][j-1];
              else 
                  dp[i][j] = dp[i+pow2[j-1]][j-1];              
           }
          
       for (int i = 0; i < q; i++) {
           scanf("%d%d", &ai, &bi);
           ai--, bi--;
           int a = r[ai], b = r[bi];
           rmq(min(a, b), max(a, b), d);
           printf("%d\n", e[a] + e[b] - 2 * d);
       }
       printf("\n");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值