CF1280D Miss Punyverse

看完题容易转化为,划分连通块,每个连通块权值为 \(val=\sum w-\sum b\) 要求最大化 \(val>0\) 的连通块数量。

设计状态 \(f_{u,i}\) 表示 \(u\) 子树内 \(i\) 个连通块除去 \(u\) 所在连通块最大的合法连通块数。发现无法转移,因为合并 \(u,v\) 时需要考虑 \(u,v\) 分别在的连通块的权值。

也就是影响转移决策的有两个因素,一个是合法连通块的数量,一个是 \(u\) 所在连通块的权值。考虑哪个因素的优先级比较高。发现无论 \(u\) 所在连通块权值多大最后合并时最多增加一个合法连通块数。所以就显然了,在保证合法连通块数尽量多的情况下保证 \(u\) 所在连通块权值尽量大,于是树上背包简单 dp 分情况讨论 \(u,v\) 所在连通块是否合并转移即可。

#include<bits/stdc++.h>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){
    ll x=0,f=1;char ch=nc();
    while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
    while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
   	return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
inline int pcount(ll x){
	for(int i=0,res=0;;res+=(x>>i)&1,i++)
		if(i>60)return res;
}

//struct mt{
//	ll v;
//	mt(){v=0;}
//	mt(int x){this->v=x;}
//	inline mt operator+(mt x){return {(v+x.v)%mod};}
//	inline mt operator-(mt x){return {(v+mod-x.v)%mod};}
//	inline mt operator*(mt x){return {1ll*v*x.v%mod};}
//};
//mt qp(mt x,int y){mt res(1);for(;y;x=x*x,y>>=1)if(y&1)res=res*x;return res;}
const int N=3005;
vector<int>e[N];
ll f[N][N],g[N][N],w[N],b[N],siz[N],tf[N],tg[N];
void dfs(int u,int fa){
	siz[u]=1,g[u][1]=w[u]-b[u];
	for(int v:e[u])if(v^fa){
		dfs(v,u);
		for(int i=0;i<=siz[u]+siz[v];i++)tf[i]=0,tg[i]=-1e15;
		for(int i=1;i<=siz[u];i++)
			for(int j=1,tmp;j<=siz[v];j++){
				tmp=f[u][i]+f[v][j]+(g[v][j]>0);
				if(tmp>tf[i+j])
					tf[i+j]=tmp,tg[i+j]=g[u][i];
				else if(tmp==tf[i+j])tg[i+j]=max(tg[i+j],g[u][i]);
				tmp=f[u][i]+f[v][j];
				if(tmp>tf[i+j-1])
					tf[i+j-1]=tmp,tg[i+j-1]=g[u][i]+g[v][j];
				else if(tmp==tf[i+j-1])tg[i+j-1]=max(tg[i+j-1],g[u][i]+g[v][j]);
			}
		siz[u]+=siz[v];
		for(int i=0;i<=siz[u];i++)
			f[u][i]=tf[i],g[u][i]=tg[i];
	}
}
inline void UesugiErii(){
	int n,m;cin>>n>>m;
	intz(f,0),intz(g,0xcf);
	for(int i=1;i<=n;i++)e[i].clear(); 
	for(int i=1;i<=n;i++)cin>>b[i];
	for(int i=1;i<=n;i++)cin>>w[i];
	for(int i=1,u,v;i<n;i++)
		cin>>u>>v,e[u].pb(v),e[v].pb(u);
	dfs(1,0);
//	cout<<f[1][m]<<' '<<g[1][m]<<'\n';
	cout<<f[1][m]+(g[1][m]>0)<<'\n';
}
signed main(){
	//IO();
	cfast;
	int _=1;cin>>_;
	for(;_;_--)UesugiErii();
	return 0;
}
posted @ 2025-11-18 16:30  Uesugi1  阅读(3)  评论(0)    收藏  举报