ARC111B Reversible Cards 题解 (套路题)

考虑将 \(a_i,b_i\) 之间连边,发现题目可以被转化为给定一个图,要求对于每条边将其一个顶点染色,问最多能将多少个点染色。

于是我们对于每个连通块分开来考虑。对于一个连通块,注意到我们不能将每个顶点染色当且仅当这个连通块是树,且此时可以染色的定点数量为连通块大小减一,如下:

  1. 如果当前连通块是树,则我们可以固定一个点作为根节点,其余所有非根节点,用它连向父亲的那条边对他进行染色。
  2. 如果当前连通块不是树,则我们可以求出他的一个生成树,以一个在环中的节点作为根节点,以 (1) 的方案将这个连通块除了这个根节点以外的点染色,接下来用这个环上的与根节点连接的非树边将这个根节点染色。

于是得证,时间复杂度 \(O(n+V)\)

const int MAXN = 4e5 + 5;
int n, a[MAXN], vis[MAXN], b[MAXN], sz[MAXN];
vector<int> G[MAXN];

bool dfs(int x, int fa) {
	vis[x] = true; sz[x] = 1;
	auto res = true;
	for (auto u:G[x]) {
		if (u == fa) continue;
		if (vis[u]) res = false;
		else res &= dfs(u, x), sz[x] += sz[u];
	}
	return res;
}

void work() {
	cin >> n;
	for (int i = 1; i <= n; ++i) {
        cin >> a[i] >> b[i];
		G[a[i]].push_back(b[i]);
		G[b[i]].push_back(a[i]);
	}
	int N = max(*max_element(a + 1, a + 1 + n), *max_element(b + 1, b + 1 + n)), ans = 0;
	for (int i = 1; i <= N; ++i) {
		if (vis[i]) continue;
		auto res = dfs(i, 0);
		if (res) ans += sz[i] - 1;
		else ans += sz[i];
	}
	cout << ans << endl;
}
posted @ 2024-02-21 11:39  小蛐蛐awa  阅读(34)  评论(0)    收藏  举报