AcWing 397 Tarjan e-DCC + 倍增 LCA

题意

传送门 AcWing 397 逃不掉的路

题解

e − D C C e-DCC eDCC 中不存在割边,那么 e − D C C e-DCC eDCC 中各点与相连的割边端点至少存在两条不重叠的路径,而割边是两个相邻连接的 e − D C C e-DCC eDCC 的必经边。

T a r j a n Tarjan Tarjan 算法求解 e − D C C e-DCC eDCC,缩点建图,得到一颗树。对每个询问使用倍增 L C A LCA LCA 求解路径端点所在 e − D C C e-DCC eDCC 间的距离,因为边权为 1 1 1,则这个距离即答案。总时间复杂度 O ( M + ( N + Q ) log ⁡ N ) O(M+(N+Q)\log N) O(M+(N+Q)logN)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005, maxm = 2 * 200005, maxlg = 18;
int N, M, Q, num, dcc, dfn[maxn], low[maxn], dc[maxn];
int tot, head[maxn], to[maxm], nxt[maxm];
int tot_c, hc[maxn], tc[maxm], nc[maxm];
int lg[maxn], fa[maxn][maxlg], dep[maxn];
bool bg[maxm];

inline void add(int x, int y) {
    
     to[++tot] = y, nxt[tot] = head[x], head[x] = tot; }

inline void add_c(int x, int y) {
    
     tc[++tot_c] = y, nc[tot_c] = hc[x], hc[x] = tot_c; }

void tarjan(int x, int in)
{
    
    
    low[x] = dfn[x] = ++num;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i];
        if (!dfn[y])
        {
    
    
            tarjan(y, i);
            low[x] = min(low[x], low[y]);
            if (low[y] > dfn[x])
                bg[i] = bg[i ^ 1] = 1;
        }
        else if (i != (in ^ 1))
            low[x] = min(low[x], dfn[y]);
    }
}

void dfs(int x)
{
    
    
    dc[x] = dcc;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i];
        if (!dc[y] && !bg[i])
            dfs(y);
    }
}

void dfs2(int x, int f, int d)
{
    
    
    fa[x][0] = f, dep[x] = d;
    for (int k = 1; k <= lg[d]; ++k)
        fa[x][k] = fa[fa[x][k - 1]][k - 1];
    for (int i = hc[x]; i; i = nc[i])
    {
    
    
        int y = tc[i];
        if (y != f)
            dfs2(y, x, d + 1);
    }
}

int lca(int x, int y)
{
    
    
    if (dep[x] < dep[y])
        swap(x, y);
    while (dep[x] > dep[y])
        x = fa[x][lg[dep[x] - dep[y]]];
    if (x == y)
        return x;
    for (int k = lg[dep[x]]; k >= 0;)
        if (fa[x][k] != fa[y][k])
            x = fa[x][k], y = fa[y][k], k = lg[dep[x]];
        else
            --k;
    return fa[x][0];
}

int main()
{
    
    
    scanf("%d%d", &N, &M);
    tot = tot_c = 1;
    for (int i = 1, x, y; i <= M; ++i)
        scanf("%d%d", &x, &y), add(x, y), add(y, x);
    tarjan(1, 0);
    for (int i = 1; i <= N; ++i)
        if (!dc[i])
            ++dcc, dfs(i);
    for (int i = 2; i <= tot; ++i)
    {
    
    
        int x = dc[to[i ^ 1]], y = dc[to[i]];
        if (x != y)
            add_c(x, y);
    }
    lg[0] = -1;
    for (int i = 1; i <= N; ++i)
        lg[i] = lg[i - 1] + (i == (1 << (lg[i - 1] + 1)));
    dfs2(1, 0, 0);
    scanf("%d", &Q);
    for (int i = 1, x, y; i <= Q; ++i)
    {
    
    
        scanf("%d%d", &x, &y);
        x = dc[x], y = dc[y];
        int z = lca(x, y);
        printf("%d\n", dep[x] + dep[y] - (dep[z] << 1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/114949510
今日推荐