CF375E Red and Black Tree

2022/8/31 23:26:17

本文主要是介绍CF375E Red and Black Tree,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

题目传送门

Solution

非常神奇的一道题。

我们不考虑交换操作,相反,我们去考虑把多少个 \(0\) 的位置变为 \(1\),同时我们记录选了多少个黑点,如果跟原来黑点数量相同即是合法。

此时我们可以发现一个神奇的性质对于 \(u\) 的儿子 \(v\),如果覆盖 \(u\) 的节点不覆盖 \(v\),那么覆盖 \(v\) 的节点在 \(v\) 的子树内的时候最优,因为不在的话会让覆盖 \(u\) 的节点变成覆盖 \(v\) 的节点。

所以我们可以考虑设 \(f_{u,i,k}\) 表示以 \(u\) 为根的子树,选了 \(i\) 个黑点,覆盖 \(u\) 的节点是 \(k\) 的最小需要把多少个白点变为黑点,然后我们可以树上背包。复杂度显然 \(\Theta(n^3)\)。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 505
#define sh short

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

#define pii pair<int,int>
#define se second
#define fi first
vector <pii> g[MAXN];

int n,X,tot,col[MAXN];
sh f[MAXN][MAXN][MAXN],h[MAXN][MAXN],miv[MAXN][MAXN];

int ind,tur[MAXN],dfn[MAXN],siz[MAXN];
void dfs (int u,int fa){
	dfn[u] = ++ ind,tur[ind] = u;
	for (pii it : g[u]){
		int v = it.fi;
		if (v ^ fa) dfs (v,u);
	}
}

void getdis (int u,int rt,int fa,int dis){
	if (u == rt) f[u][1][dfn[u]] = 1 ^ col[u];
	else f[rt][0][dfn[u]] = 0;
	for (pii it : g[u]){
		int v = it.fi,w = it.se;
		if (v != fa && dis + w <= X) getdis (v,rt,u,dis + w);
	}
}

void dfs1 (int u,int fa){
	siz[u] = 1;
	for (pii it : g[u]){
		int v = it.fi;
		if (v == fa) continue;
		dfs1 (v,u);
		for (Int i = 0;i <= siz[u];++ i) for (Int t = 1;t <= n;++ t) h[i][t] = f[u][i][t],f[u][i][t] = 0x3f3f;
		for (Int i = 0;i <= siz[u];++ i) for (Int t = 1;t <= n;++ t){
			for (Int j = 0;j <= siz[v] && i + j <= tot;++ j){
				chkmin (f[u][i + j][t],(sh)(h[i][t] + f[v][j][t]));
				if (t < dfn[v] || t >= dfn[v] + siz[v])
					chkmin (f[u][i + j][t],(sh)(h[i][t] + miv[v][j]));
			}
		}
		siz[u] += siz[v];
	}
	for (Int i = 0;i <= siz[u];++ i){
		miv[u][i] = 0x3f3f;
		for (Int k = dfn[u];k <= dfn[u] + siz[u] - 1;++ k) chkmin (miv[u][i],f[u][i][k]);
	}
}

signed main(){
	read (n,X);
	for (Int x = 1;x <= n;++ x) read (col[x]),tot += col[x];
	for (Int i = 2,u,v,w;i <= n;++ i) read (u,v,w),g[u].push_back ({v,w}),g[v].push_back ({u,w});
	dfs (1,0),memset (f,0x3f,sizeof (f));
	for (Int u = 1;u <= n;++ u) getdis (u,u,u,0);
	dfs1 (1,0);sh ans = n + 1;
	for (Int i = 0;i <= tot;++ i)
		for (Int j = 1;j <= n;++ j) 
			chkmin (ans,f[1][i][j]);
	write (ans == n + 1 ? -1 : ans),putchar ('\n');
	return 0;
}


这篇关于CF375E Red and Black Tree的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程