1 条题解
-
0
自动搬运
来自洛谷,原作者为

TonyYuan
「时间不会停下脚步,而时光愿为你片刻驻留」搬运于
2025-08-24 22:06:40,当前版本为作者最后更新于2020-03-25 08:51:57,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
(更新排版及原题解数据范围,感谢@♗Wendigo♝)
考虑缩点时的过程,设是的祖先,我们通过找为根的搜索子树是否能延伸到时间戳小于的节点来判断u是否为割点。如果该子树不能延伸至以上,则去掉后该子树会与其余部分“失去联系”。
由此我们这样想:如果我们以一个信息中心为根开始搜索,找到一个非根的割点;此时若对应的子树根的时间戳小于等于的时间戳,则说明存在于的子树内。
这很显然,由于随序更新,若还没搜到,则其为;或者不为而小于,则说明在进入以前已经被搜到了。
那么如果把断掉,的整棵子树都会与根失去联系,就是所求的点之一。
算法只对原函数的判断条件略做了修改,因此效率得到了极大保留,时间复杂度。
#include <iostream> #include <algorithm> #include <vector> #include <cstdio> #include <queue> const int maxn(200010); const int maxm = 500010; using namespace std; int top = 1, head[maxn], n, a, b; struct node { int to, nxt; } edge[maxm<<1]; void tarjan(int); bool cut[maxn]; inline void insert(int u, int v) { edge[++top] = (node) {v, head[u]}; head[u] = top; } int main() { scanf("%d", &n); int u, v; scanf("%d %d", &u, &v); while (!(u==0 && v==0)) { insert(u, v), insert(v, u); scanf("%d %d", &u, &v); } scanf("%d %d", &a, &b); tarjan(a); for(int i = 1; i <= n; i++) if(cut[i]) { printf("%d", i); return 0; } puts("No solution"); return 0; } int dfn[maxn], low[maxn], timer; void tarjan(int u) { dfn[u] = low[u] = ++timer; for(int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].to; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); if(low[v]>=dfn[u] && u!=a && dfn[b]>=dfn[v]) cut[u] = 1; } else low[u] = min(low[u], dfn[v]); } return; }
- 1
信息
- ID
- 4066
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者