You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

ZJOI 2004 嗅探器

一、题目大意

给出一张无向图以及两个点 rooted,找出一个编号最小的并且在所有rooted 的路径上的点。

二、解题思路

  考虑缩点时的过程,设uv的祖先,我们通过找v为根的搜索子树是否能延伸到时间戳小于u的节点来判断u是否为割点。如果该子树不能延伸至u以上,则去掉u后该子树会与其余部分 失去联系

  由此我们这样想:如果我们以一个信息中心root为根开始搜索,找到一个非根的割点u;此时若对应的子树根v的时间戳小于等于b的时间戳,则说明b存在于v的子树内。

  这很显然,由于dfndfs序更新,若还没搜到b,则其dfn0;或者dfn不为0而小于v,则说明b在进入v以前已经被搜到了。

  那么如果把u断掉,v的整棵子树都会与根root失去联系,u就是所求的点之一。

  算法只对原Tarjan函数的判断条件略做了修改,因此效率得到了极大保留,时间复杂度 O(n+m)

三、实现代码

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 200010, M = N << 1;
int n;
bool st[N];
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int ans = INF;
int root, ed;

// Tarjan算法求割点
int dfn[N], low[N], ts;
void tarjan(int u, int fa) {
    low[u] = dfn[u] = ++ts;

    for (int i = h[u]; ~i; i = ne[i]) {
        int v = e[i];
        if (v == fa) continue;
        if (!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            // u是割点
            if (u != root && low[v] >= dfn[u]) {
                if (u == ed) continue; // 根据题意u必须在root和ed之间
                if (dfn[ed] >= dfn[v]) ans = min(ans, u);
            }
        } else
            low[u] = min(low[u], dfn[v]);
    }
}

int main() {
    // 初始化链式前向星
    memset(h, -1, sizeof h);

    scanf("%d", &n);
    int x, y;
    while (scanf("%d %d", &x, &y), x || y)
        if (x != y) add(x, y), add(y, x);

    scanf("%d %d", &root, &ed);
    tarjan(root, -1); // 从其中一个信息中心开始遍历

    if (ans == INF)
        printf("No solution");
    else
        printf("%d", ans);
    return 0;
}