洛谷P3388 【模板】割点(割顶)

题目链接:

kma!

题目分析:

割点模板,对于当前搜索的节点是不是搜索树里的根节点分类讨论

  • 如果是根节点,显然如果它的子树数量\(>=2\),把它\(cut\)掉两棵子树就不连通了
  • 如果不是根节点,如果有搜到的节点\(low[v] >= dfn[u]\),说明有节点不通过\(u\)没办法上翻到环外,那么把它\(cut\)掉也是可行的
    没了

代码:

#include <bits/stdc++.h>
#define N (300000 + 10)
using namespace std;
inline int read() {
	int cnt = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
	while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
	return cnt * f;
}
int nxt[N], first[N], to[N], tot, sign, low[N], dfn[N], cnt;
int ans[N], son[N], flag;
void Add(int x, int y) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y;}
void tarjan (int u, int fa) {
	dfn[u] = low[u] = ++sign;
	for (register int i = first[u]; i; i = nxt[i]) {
		if (!dfn[to[i]]) {
			tarjan(to[i], fa), low[u] = min(low[u], low[to[i]]);
			if (u == fa) ++son[u]; 
			if (low[to[i]] >= dfn[u] && u != fa) ans[++cnt] = u;
		}
		else if (dfn[to[i]] < low[u]) low[u] = min(low[u], dfn[to[i]]);
	}
	if (u == fa && son[u] >= 2) ans[++cnt] = u;
}
int n, m, x, y;
int main() {
//	freopen("1.in", "r", stdin);
	n = read(), m = read();
	for (register int i = 1; i <= m; i++) {
		x = read(), y = read();
		Add(x, y), Add(y, x);
	}
	for (register int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, i);
	sort(ans + 1, ans + cnt + 1);
	int q = unique (ans + 1, ans + cnt + 1) - ans - 1; 
	printf("%d\n", q);
	for (register int i = 1; i <= q; i++) printf("%d ", ans[i]); 
	return 0;
}
posted @ 2019-08-10 16:18  kma_093  阅读(99)  评论(0编辑  收藏  举报