P6326 Shopping

题目

P6326 Shopping

分析

首先发现很明显是树上多重背包。

于是可以考虑设状态 \(dp[x][i]\) 表示(必选\(x\))和其子树连通块,且背包容量为 \(i\) 时的最大价值。

直接单调队列 \(dp\) ,明显是 \(O(n^2m)\)

那么考虑优化,我们发现这里的难点无非就是要处理每一个点作为当前根,那么我们直接考虑点分治,然后根节点必选即可。

同时,我们还是也可以考虑暴力枚举,因为这里没有强制在线,所以直接启发式合并也可以做到 \(O(nmlogn)\)

这里可以用二进制优化,好像还跑的快点,代码细节见这里

代码

这里是点分治做法。

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
} 
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
const int N=1005,V=4005;
int t,n,m,Ans;
int head[N],nex[N],to[N],idx;
inline void add(int u,int v){
	nex[++idx]=head[u];
	to[idx]=v;
	head[u]=idx;
	return ;
}
int w[N],c[N],d[N];
int Root,FMax,siz[N],Size;
bool vis[N];
void GetRoot(int x,int fa){
	siz[x]=1;int Max=0;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(y==fa||vis[y]) continue;
		GetRoot(y,x);siz[x]+=siz[y];
		Max=max(Max,siz[y]);
	}
	Max=max(Max,Size-siz[x]);
	if(Max<=FMax) FMax=Max,Root=x;
	return ;
}
int dp[N][V];
void DP(int x,int fa,int lim){
	if(lim-c[x]<0) return ;
	int num=d[x]-1;
	const int v=lim-c[x];
	for(int i=0;i<=v;i++) dp[x][i]=dp[fa][i]+w[x];
	for(int i=0;(1<<i)<=num;i++){
		const int tmp=(1<<i);
		for(int j=v;j>=c[x]*tmp;j--) dp[x][j]=max(dp[x][j],dp[x][j-c[x]*tmp]+w[x]*tmp);
		num-=tmp; 
	}
	if(num){
		const int tmp=num;
		for(int j=v;j>=c[x]*tmp;j--) dp[x][j]=max(dp[x][j],dp[x][j-c[x]*tmp]+w[x]*tmp);
		num-=tmp;
	}
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(y==fa||vis[y]) continue;
		DP(y,x,v); 
		for(int j=c[y];j<=v;j++) dp[x][j]=max(dp[x][j],dp[y][j-c[y]]);
	}
	return ;
}
void Update(int x,int fa){
	DP(x,0,m);
	for(int i=0;i<=m-c[x];i++) Ans=max(Ans,dp[x][i]);
	return ;
}
void DFS(int x,int fa){
	vis[x]=true;Update(x,fa);
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(vis[y]) continue;
		Size=FMax=siz[y],Root=y,GetRoot(y,x),DFS(Root,x); 
	}
	vis[x]=false;
	return ;
}	 
signed main(){
	read(t);
	while(t--){
		read(n),read(m);
		idx=0;Ans=0;
		memset(head,0,sizeof(head));
		for(int i=1;i<=n;i++) read(w[i]);
		for(int i=1;i<=n;i++) read(c[i]);
		for(int i=1;i<=n;i++) read(d[i]);
		for(int i=1;i<n;i++){
			int u,v;
			read(u),read(v);
			add(u,v),add(v,u);
		}
		Size=FMax=n,Root=0,GetRoot(1,0),DFS(Root,0); 
		write(Ans),putchar('\n');
	}
	return 0;
}
posted @ 2021-05-03 23:51  __Anchor  阅读(41)  评论(0编辑  收藏  举报