hdu 2874 lca-tarjan离线算法(模板)

本文介绍了一种使用LCA-Tarjan算法解决带有权重的森林中点间最短路径问题的方法。通过构建森林的LCA模型并利用Tarjan算法进行遍历,实现了高效的查询处理。对于每个询问,算法能够确定两点是否属于同一联通块,并计算它们之间的最短距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

给n个点,m条边带权值的森林,然后q(10^6)次询问,询问每个点之间的最短距离,若两点不属于同一个联通块,则输出not ...


解析:

新学了一种lca-tarjan的模板,看起来稳多了。

这题是遍历所有的点,把森林中的也变成lca。

然后记录答案,最后如果答案被修改过,就输出,如果为-1,则点没有被连到。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

const int maxn = 10000 + 10;
const int maxm = 20000 + 10;
const int maxq = 2000000 + 10;

int n, m, q;
int dis[maxn], vis[maxn], ancestor[maxn];
int ans[maxq >> 1];

struct Edge
{
    int to, next;
    int len;
} edge[maxm];

int edgeNum;
int edgeHead[maxn];
void addEdge(int fr, int to, int len)
{
    edge[edgeNum].to = to;
    edge[edgeNum].len = len;
    edge[edgeNum].next = edgeHead[fr];
    edgeHead[fr] = edgeNum++;

    edge[edgeNum].to = fr;
    edge[edgeNum].len = len;
    edge[edgeNum].next = edgeHead[to];
    edgeHead[to] = edgeNum++;
}

struct Query
{
    int to, next;
    int id;
} query[maxq];

int queryNum;
int queryHead[maxn];
void addQuery(int fr, int to, int id)
{
    query[queryNum].to = to;
    query[queryNum].id = id;
    query[queryNum].next = queryHead[fr];
    queryHead[fr] = queryNum++;

    query[queryNum].to = fr;
    query[queryNum].id = id;
    query[queryNum].next = queryHead[to];
    queryHead[to] = queryNum++;
}

int Find(int x)
{
    if (ancestor[x] == x)
        return x;
    return ancestor[x] = Find(ancestor[x]);
}

void lca(int u, int dep, int rt)
{
    ancestor[u] = u;
    vis[u] = rt;
    dis[u] = dep;

    for (int i = edgeHead[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (vis[v] == -1)
        {
            lca(v, dep + edge[i].len, rt);
            ancestor[v] = u;
        }
    }
    for (int i = queryHead[u]; i != -1; i = query[i].next)
    {
        int v = query[i].to;
        if (vis[v] == rt)
        {
            //ans[query[i].id] = ancestor[Find(v)]
            ans[query[i].id] = dis[v] + dis[u] - 2 * dis[Find(v)];
        }
    }
}

void init()
{
    edgeNum = 0;
    queryNum = 0;
    memset(edgeHead, -1, sizeof(edgeHead));
    memset(queryHead, -1, sizeof(queryHead));
    memset(vis, -1, sizeof(vis));
    memset(ans, -1, sizeof(ans));
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    while (~scanf("%d%d%d", &n, &m, &q))
    {
        init();
        while (m--)
        {
            int fr, to, len;
            scanf("%d%d%d", &fr, &to, &len);
            addEdge(fr, to, len);
        }
        for (int i = 0; i < q; i++)
        {
            int fr, to;
            scanf("%d%d", &fr, &to);
            ans[i] = -1;
            addQuery(fr, to, i);
        }
        for (int i = 1; i <= n; i++)
        {
            if (vis[i] == -1)
            {
                lca(i, 0, i);
            }
        }
        for (int i = 0; i < q; i++)
        {
            if (ans[i] == -1)
            {
                puts("Not connected");
            }
            else
            {
                printf("%d\n", ans[i]);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值