天天看点

poj1986 LCA转化为RMQ在线算法模板题

 分析:这道题就是求一个最近公共祖先,然后结果就是两点到根的距离减去LCA(u, v)到根的距离。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
const int maxn = 100000 + 5;
struct Eage{
    int to, next, w;
}eage[maxn*2];
int cnt, tim = 0, n, depth = 0;
int head[maxn];
int pos[maxn];//节点在深度序列中首次出现的深度
int f[maxn];//深搜序列
int b[maxn*2];//深度序列,注意每个节点的深度是不同的
ll dis[maxn];//节点到根的距离
int dp[maxn][15];
void add(int x, int y, int z)
{
    eage[cnt].to = y;
    eage[cnt].w = z;
    eage[cnt].next = head[x];
    head[x] = cnt++;
}

void dfs1(int u, int fa)
{
    //cout << u << " ";
    int deep = ++depth;
    f[deep] = u;
    b[++tim] = deep;
    pos[u] = tim;
    for (int i = head[u]; i != -1; i = eage[i].next)
    {
        int v = eage[i].to;
        if (v == fa) continue;
        dis[v] = dis[u] + eage[i].w;
        dfs1(v, u);
        b[++tim] = deep;
    }
}
void rmq_st(int n)
{
    for (int i = 1; i <= n; i++) dp[i][0] = b[i];
    int m = (int) (log(1.0*n)/log(2.0));//注意括号
    for (int j = 1; j <= m; j++)
    {
        int t = n - (1<<j)+1;
        for (int i = 1; i <= t; i++)
        {
            if (dp[i][j-1] < dp[i+(1<<(j-1))][j-1]) {
                dp[i][j] = dp[i][j-1];
            }
            else {
                dp[i][j] = dp[i+(1<<(j-1))][j-1];
            }
        }
    }
}
int rmq_find(int l, int r)
{
    int k = (int)(log(1.0*(r-l+1)) / log(2.0));
    return min(dp[l][k], dp[r-(1<<k)+1][k]);
}

int main()
{
    //freopen("input.txt", "r", stdin);
    int  m;
    cin >> n >> m;
    cnt = 0;
    tim = 0;
    memset(head, -1, sizeof(head));
    memset(pos, -1, sizeof(pos));
    memset(dis, 0, sizeof(dis));
    for (int i = 1; i <= m; i++)
    {
        int x, y, z;
        char ch;
        scanf("%d%d%d %c", &x, &y, &z, &ch);
        add(x, y, z);
        add(y, x, z);
    }
    dfs1(1, 0);
    rmq_st(2*n-1);
    int k;
    cin >> k;
    for (int i = 0; i < k; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if (pos[a] > pos[b]) swap(a, b);
        int  k = rmq_find(pos[a], pos[b]);
        cout << dis[a]+dis[b]-2*dis[f[k]] << endl;
    }
    return 0;
}