CodeForces 1218A BubbleReactor

洛谷传送门

CF 传送门

虚高 *2800。放模拟赛 T2 人均切了。

考虑拎出环上的点,每个点下面都挂了一棵树。

那么可以预处理出每棵树从一个点开始染黑,这棵树对答案的贡献。因为一棵树染了一个点就只能去染子树了,所以这个贡献是固定的,用换根 dp 求即可。

那么我们现在可以在环上选择一个起点,每次可以把左端点或右端点往外拓展 \(1\)。拓展的贡献就是除了已经拓展的点外其他点挂的树的 \(sz\) 之和,加上要拓展的点的所有子树 \(sz\) 和。

套路区间 dp 即可。设 \(f_{i, j}\) 为已经拓展了环上在 \([i, j]\) 中的点即可。注意因为是个环所以 \(i > j\)\(f_{i, j}\) 表示已经拓展了环上在 \([i, m] \cup [1, j]\) 的点,其中 \(m\) 为环上的点数。

按长度从小到大枚举,就可以滚动数组了。

时间复杂度 \(O(n + m^2)\)。实际跑得挺快。

code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 15010;

int n, m;
vector<int> G[maxn];

int deg[maxn], g[maxn], sz[maxn], h[maxn];
int f[2][maxn], a[maxn], b[maxn], c[maxn], mx;

void dfs(int u, int fa) {
	sz[u] = 1;
	for (int v : G[u]) {
		if (v == fa || deg[v]) {
			continue;
		}
		dfs(v, u);
		sz[u] += sz[v];
		g[u] += g[v];
	}
	g[u] += sz[u];
}

void dfs2(int u, int fa) {
	mx = max(mx, h[u]);
	for (int v : G[u]) {
		if (v == fa || deg[v]) {
			continue;
		}
		h[v] = h[u] + n - sz[v] * 2;
		dfs2(v, u);
	}
}

bool vis[maxn];
int p[maxn];

void dfs3(int u) {
	vis[u] = 1;
	p[m++] = u;
	for (int v : G[u]) {
		if (deg[v] && !vis[v]) {
			dfs3(v);
			break;
		}
	}
}

void solve() {
	scanf("%d", &n);
	for (int _ = 0, u, v; _ < n; ++_) {
		scanf("%d%d", &u, &v);
		++u;
		++v;
		++deg[u];
		++deg[v];
		G[u].pb(v);
		G[v].pb(u);
	}
	m = 0;
	queue<int> q;
	for (int i = 1; i <= n; ++i) {
		if (deg[i] == 1) {
			q.push(i);
		}
	}
	while (q.size()) {
		int u = q.front();
		q.pop();
		deg[u] = 0;
		for (int v : G[u]) {
			if (deg[v] && (--deg[v]) == 1) {
				q.push(v);
			}
		}
	}
	for (int i = 1; i <= n; ++i) {
		if (deg[i]) {
			dfs3(i);
			break;
		}
	}
	for (int i = 0; i < m; ++i) {
		int u = p[i];
		dfs(u, -1);
		h[u] = g[u] + n - sz[u];
		mx = 0;
		dfs2(u, -1);
		a[i] = g[u];
		b[i] = mx;
		c[i] = sz[u];
	}
	for (int i = 1; i < m; ++i) {
		c[i] += c[i - 1];
	}
	mems(f, -0x3f);
	for (int i = 0; i < m; ++i) {
		f[1][i] = b[i];
	}
	for (int p = 2, o = 0; p <= m; ++p, o ^= 1) {
		mems(f[o], -0x3f);
		for (int i = 0, j = p - 1; i < m; ++i, j = (j == m - 1 ? 0 : j + 1)) {
			f[o][i] = max(f[o ^ 1][i] + a[j], f[o ^ 1][i == m - 1 ? 0 : i + 1] + a[i]);
			if (p < m) {
				f[o][i] += c[m - 1];
				if (i <= j) {
					f[o][i] -= c[j] - (i == 0 ? 0 : c[i - 1]);
				} else {
					f[o][i] -= c[m - 1] - c[i - 1] + c[j];
				}
			}
		}
	}
	int ans = 0;
	for (int i = 0; i < m; ++i) {
		ans = max(ans, f[m & 1][i]);
	}
	printf("%d\n", ans);
}

int main() {
	// freopen("B.in", "r", stdin);
	// freopen("my.out", "w", stdout);
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2024-01-23 11:29  zltzlt  阅读(14)  评论(0)    收藏  举报