码迷,mamicode.com
首页 > 其他好文 > 详细

luoguP6326 Shopping

时间:2020-06-05 15:05:32      阅读:53      评论:0      收藏:0      [点我收藏+]

标签:枚举   i++   roo   ping   val   print   www   memset   树形dp   

题意

考虑点分治来枚举树上联通块,对于一个联通块,我们做有依赖性的树形DP即可,需要用单调队列优化多重背包。

有依赖性的树形DP

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=510;
const int maxm=4010;
int T,n,m,ans;
int val[maxn],cost[maxn],num[maxn];
inline int read()
{
    char c=getchar();int res=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘)res=res*10+c-‘0‘,c=getchar();
    return res*f;
}
int cnt_edge;
int head[maxn];
struct edge{int to,nxt;}e[maxn<<1];
inline void add_edge(int u,int v)
{
	e[++cnt_edge]=(edge){v,head[u]};
	head[u]=cnt_edge;
}
int root,trsize;
int size[maxn],maxs[maxn];
bool vis[maxn];
void getroot(int x,int fa)
{
	size[x]=1;maxs[x]=0;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==fa||vis[y])continue;
		getroot(y,x);size[x]+=size[y];
		maxs[x]=max(maxs[x],size[y]);
	}
	maxs[x]=max(maxs[x],trsize-size[x]);
	if(maxs[x]<maxs[root])root=x;
}
int cnt;
int a[maxn],q[maxn];
int f[maxn][maxm];
void dfs(int x,int fa)
{
	size[a[++cnt]=x]=1;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==fa||vis[y])continue;
		dfs(y,x);size[x]+=size[y];
	}
}
inline void dp()
{
	for(int i=cnt;i;i--)
	{
		int x=a[i];
		for(int j=1;j<=m;j++)f[i][j]=f[i+size[x]][j];
		for(int j=0;j<cost[x];j++)
		{
			int l=1,r=0,up=(m-j)/cost[x];
			for(int k=up-1;k>=max(0,up-num[x]);k--)
			{
				while(l<=r&&f[i+1][j+q[r]*cost[x]]-q[r]*val[x]<=f[i+1][j+k*cost[x]]-k*val[x])r--;
				q[++r]=k;
			}
			for(int k=up;~k;k--)
			{
				while(l<=r&&q[l]>k-1)l++;
				if(l<=r)f[i][j+k*cost[x]]=max(f[i][j+k*cost[x]],f[i+1][j+q[l]*cost[x]]+(k-q[l])*val[x]);
				if(k-num[x]-1>=0)
				{
					int now=k-num[x]-1;
					while(l<=r&&f[i+1][j+q[r]*cost[x]]-q[r]*val[x]<=f[i+1][j+now*cost[x]]-now*val[x])r--;
					q[++r]=now;
				}
			}
		}
	}
	for(int i=0;i<=m;i++)ans=max(ans,f[1][i]);
	for(int i=1;i<=cnt;i++)
		for(int j=0;j<=m;j++)
			f[i][j]=0;
}
void solve(int x)
{
	cerr<<"now::"<<x<<endl;
	vis[x]=1;
	cnt=0;dfs(x,0);dp();
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(vis[y])continue;
		trsize=size[y],root=0,getroot(y,0),solve(root);
	}
}
inline void solve()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)val[i]=read();
	for(int i=1;i<=n;i++)cost[i]=read();
	for(int i=1;i<=n;i++)num[i]=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		add_edge(u,v),add_edge(v,u);
	}
	trsize=maxs[root=0]=n;getroot(1,0);solve(root);
	printf("%d\n",ans);
}
inline void init()
{
	memset(head,0,sizeof(head));
	memset(vis,0,sizeof(vis));
	cnt_edge=ans=0;
}
int main()
{
	int T=read();
	while(T--)init(),solve();
	return 0;
}

luoguP6326 Shopping

标签:枚举   i++   roo   ping   val   print   www   memset   树形dp   

原文地址:https://www.cnblogs.com/nofind/p/13049552.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!