Tarjan算法求LCA

题源:https://loj.ac/problem/10130

这个题还是debug了好久。。

1.调用函数中如果要更改外部数据需要传递引用,其实传递引用往往效率更高,以后要多加注意这一点。

2.忘写并查集了(捂脸逃)

3.题目要求的是距离而不是lca,认真审题。。

贴代码:

#include <iostream>
#include <stdio.h>
#include <cstring>
#define maxn 100005
//#define LOCAL
using namespace std;
struct Edge
{
    int next, to, dis;
} edge[maxn * 2], queryEdge[maxn * 2]; //两倍存储(不知道父子关系与遍历的先后顺序)
int head[maxn], queryHead[maxn], e1 = -1, e2 = -1, fa[maxn], vs[maxn], dep[maxn]; //dep用来记录深度求距离

void addedge(int *head, Edge *edge, int &e, int x, int y) //e要传递引用来进行更改,否则++无效
{
    edge[++e].next = head[x], edge[e].to = y, head[x] = e;
    edge[++e].next = head[y], edge[e].to = x, head[y] = e;
}

int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } //居然忘写了。。

void tarjan(int u, int pre) //要多传入一个前置节点参数以更改dep,自上往下更新
{
    vs[u] = 1; dep[u] = dep[pre] + 1;
    #ifdef LOCAL
    cout << u << " : " << dep[u] << endl;
    #endif
    int v;
    for (int i = head[u]; ~i; i = edge[i].next) // ~i等同于i != -1
    {
        v = edge[i].to; 
        if (!vs[v])
        {
            tarjan(v, u); fa[v] = u; //更改dep不能放在这,这是自下往上更新
        }
    }
    for (int i = queryHead[u]; ~i; i = queryEdge[i].next)
    {
        v = queryEdge[i].to;
        if (vs[v])
        {
            queryEdge[i].dis = queryEdge[i ^ 1].dis = dep[u] + dep[v] - 2 * dep[find(v)];
        }
    }
}

int main()
{
    #ifdef LOCAL
    freopen("out.txt", "w", stdout);
    #endif
    memset(head, 0xff, sizeof(head)); //oxff全部初始化为-1
    memset(queryHead, 0xff, sizeof(queryHead));
    memset(vs, 0, sizeof(vs));
    int n, q, x, y;
    scanf("%d", &n);
    for (int i = 1; i <= n - 1; ++i)
    {
        fa[i] = i; //不要忘了初始化father数组
        scanf("%d%d", &x, &y);
        addedge(head, edge, e1, x, y);
    }
    fa[n] = n;
    scanf("%d", &q);
    for (int i = 1; i <= q; ++i)
    {
        scanf("%d%d", &x, &y);
        addedge(queryHead, queryEdge, e2, x, y);
    }
    #ifdef LOCAL
    // for (int i = 0; i <= e1; ++i) cout << i << " -> " << edge[i].to << endl;
    #endif
    dep[0] = 0;
    tarjan(1, 0); //根节点传入辅助0
    #ifdef LOCAL
    for (int i = 1; i <= n; ++i) cout << i << "->" << fa[i] << endl;
    #endif
    for (int i = 0; i < e2; i += 2)
    {
        printf("%d\n", queryEdge[i].dis);
    }
}
posted @ 2020-01-19 14:52  JonKitten  阅读(167)  评论(0编辑  收藏  举报