CF1830D Mex Tree

观察到贡献不为 22 的点对形成多个连通块,于是考虑树上背包。

fu,i,cf_{u,i,c} 表示点 uu 的子树内,点 uu 所在的连通块大小为 ii(这个连通块满足其上所有点对贡献不为 22,即所有点点权相等),点 uu 的颜色为 ccuu 子树的最大答案。

分析复杂度可知为 O(n2)\mathcal O(n^2)

考虑一种贪心,对树进行二分图染色,答案可达 n(n+1)O(n)n(n+1)-\mathcal O(n)

注意到对于一个大小为 kk 的连通块,会使答案减少 O(k2)\mathcal O(k^2)

故在一个最优性方案中,连通块大小不超过 O(n)\mathcal O(\sqrt{n})

复杂度优化为 O(nn)\mathcal O(n\sqrt n)

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
typedef vector<int> vi;
#define F(i, a, b) for(int i = a; i <= (b); ++i)
#define F2(i, a, b) for(int i = a; i < (b); ++i)
#define dF(i, a, b) for(int i = a; i >= (b); --i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug debug("Passing [%s] in LINS %d\n", __FUNCTION__, __LINE__)
#define pb push_back
#define fi first
#define se second
#define Mry debug("%.3lf MB\n", (&Mbe - &Med) / 1048576.0)
#define Try cerr << 1e3 * clock() / CLOCKS_PER_SEC << " ms\n";
typedef long long ll;
//namespace Fread {const int SIZE = 1 << 17; char buf[SIZE], *S, *T; inline char getchar() {if (S == T) {T = (S = buf) + fread(buf, 1, SIZE, stdin); if (S == T) return '\n';} return *S++;}}
//namespace Fwrite {const int SIZE = 1 << 17; char buf[SIZE], *S = buf, *T = buf + SIZE; inline void flush() {fwrite(buf, 1, S - buf, stdout), S = buf;} inline void putchar(char c) {*S++ = c;if (S == T) flush();} struct NTR {~NTR() {flush();}} ztr;}
//#ifdef ONLINE_JUDGE
//#define getchar Fread::getchar
//#define putchar Fwrite::putchar
//#endif
inline int ri() {
	int x = 0;
	bool t = 0;
	char c = getchar();
	while (c < '0' || c > '9') t |= c == '-', c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return t ? -x : x;
}
inline void wi(int x) {
	if (x < 0) {
		putchar('-'), x = -x;
	}
	if (x > 9) wi(x / 10);
	putchar(x % 10 + 48);
}
inline void wi(int x, char s) {
	wi(x), putchar(s);
}
bool Mbe;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3f;
const int _ = 2e5 + 5, Sq = sqrt(_) + 5;
int n, m, tmp[Sq + 5], sz[_];
vector<int> f[_][2];
vector<int> d[_];
void dfs(int u, int fa) {
	int sq;
	f[u][0].resize(5), f[u][1].resize(5);
	f[u][0][1] = 1, f[u][1][1] = 0;
	sz[u] = 1;
	for(int v : d[u]) if(v != fa) {
		dfs(v, u);
		int K = min(Sq, sz[v]);
		sq = min(Sq, sz[u]);
		int Sqq = min(Sq, sz[u] + sz[v]);
		F(i, 1, Sqq) tmp[i] = 0;
		F(i, 1, sq) {
			F(j, 1, K) tmp[i] = max(tmp[i], f[u][0][i] + f[v][1][j] + 2 * sz[u] * sz[v]);
			F(j, 1, min(K, Sqq - i)) tmp[i + j] = max(tmp[i + j], f[u][0][i] + f[v][0][j] - i * j + 2 * (sz[u] * sz[v]));
		}
		f[u][0].resize(Sqq + 5);
		F(i, 1, Sqq) f[u][0][i] = tmp[i];
		F(i, 1, Sqq) tmp[i] = 0;
		F(i, 1, sq) {
			F(j, 1, K) tmp[i] = max(tmp[i], f[u][1][i] + f[v][0][j] + 2 * sz[u] * sz[v]);
			F(j, 1, min(K, Sqq - i)) tmp[i + j] = max(tmp[i + j], f[u][1][i] + f[v][1][j] + 2 * (sz[u] * sz[v] - i * j));
		}
		f[u][1].resize(Sqq + 5);
		F(i, 1, Sqq) f[u][1][i] = tmp[i];
		sz[u] += sz[v];
		f[v][0].clear(), f[v][0].shrink_to_fit();
		f[v][1].clear(), f[v][1].shrink_to_fit();
	}
}
void solve() {
	n = ri();
	F(i, 1, n) d[i].clear(), d[i].shrink_to_fit();
	F(i, 1, n - 1) {
		int u = ri(), v = ri();
		d[u].pb(v), d[v].pb(u);
	}
	F(i, 0, n + 2) f[i][0].clear(), f[i][0].shrink_to_fit(), f[i][1].clear(), f[i][1].shrink_to_fit();
	dfs(1, 0);
	int ans = 0;
	F(i, 1, min(Sq, sz[1])) ans = max(ans, max(f[1][0][i], f[1][1][i]));
	cout << ans << '\n';
}

bool Med;
signed main() {
//	freopen("1.txt", "r", stdin);
	// Mry;
//	cout << Sq;
	int T = ri();
	while(T--) 
		solve();
	Try;
}
posted @ 2023-05-29 18:57  蒟蒻orz  阅读(1)  评论(0编辑  收藏  举报  来源