标签:枚举 i++ roo ping val print www memset 树形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;
}
标签:枚举 i++ roo ping val print www memset 树形dp
原文地址:https://www.cnblogs.com/nofind/p/13049552.html