题解 洛谷 P6326 【Shopping】

考虑若连通块必须包含 (x),那么就对以 (x) 为根的有根树做树形背包。

(f_{i,j}) 为考虑了 (dfs) 序中 ([i,n]) 对应的节点,体积为 (j) 的最大价值。转移分两种情况:一个是选 (i) 对应的节点,然后对该节点的物品跑多重背包,我这里用的是二进制拆分来优化。另一个是不选 (i) 对应的节点,然后从该节点子树外转移过来,这里可以在 (dfs) 序上表示转移的位置。

连通块不包含 (x) 的情况可以用点分治来递归处理。

复杂度为 (O(nmlog dlog n))

#include<bits/stdc++.h>
#define maxn 1010
#define maxm 4010
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int T,n,m,ans,tot,root,cnt;
int w[maxn],c[maxn],d[maxn],f[maxn][maxm],siz[maxn],mx[maxn],out[maxn],rev[maxn];
bool vis[maxn];
struct edge
{
    int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
    e[++edge_cnt]={to,head[from]},head[from]=edge_cnt;
}
struct node
{
    int v,w;
}p[maxn];
void dfs_root(int x,int fa)
{
    siz[x]=1,mx[x]=0;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(vis[y]||y==fa) continue;
        dfs_root(y,x),siz[x]+=siz[y];
        mx[x]=max(mx[x],siz[y]);
    }
    mx[x]=max(mx[x],tot-siz[x]);
    if(mx[x]<mx[root]) root=x;
}
void dfs_dfn(int x,int fa)
{
    rev[++cnt]=x;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(vis[y]||y==fa) continue;
        dfs_dfn(y,x);
    }
    out[x]=cnt;
}
void solve(int x)
{
    vis[x]=true,cnt=0,dfs_dfn(x,0);
    for(int i=cnt;i;--i)
    {
        int s=d[rev[i]]-1,num=0;
        for(int j=1;j<=s;s-=j,j<<=1) p[++num]={w[rev[i]]*j,c[rev[i]]*j};
        if(s) p[++num]={w[rev[i]]*s,c[rev[i]]*s};
        for(int j=m;j>=c[rev[i]];--j) f[i][j]=f[i+1][j-c[rev[i]]]+w[rev[i]];
        for(int k=1;k<=num;++k)
            for(int j=m;j>=p[k].w;--j)
                f[i][j]=max(f[i][j],f[i][j-p[k].w]+p[k].v);
        for(int j=0;j<=m;++j) f[i][j]=max(f[i][j],f[out[rev[i]]+1][j]);
    }
    ans=max(ans,f[1][m]);
    for(int i=1;i<=cnt;++i)
        for(int j=0;j<=m;++j)
            f[i][j]=0;
    int now=tot;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(vis[y]) continue;
        root=0,tot=siz[y];
        if(siz[y]>siz[x]) tot=now-siz[x];
        dfs_root(y,x),solve(root);
    }
}
void clear()
{
    edge_cnt=root=ans=0;
    memset(vis,0,sizeof(vis));
    memset(head,0,sizeof(head));
}
int main()
{
    read(T);
    while(T--)
    {
        clear(),read(n),read(m);
        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 x,y;
            read(x),read(y);
            add(x,y),add(y,x);
        }
        tot=mx[0]=n,dfs_root(1,0),solve(root),printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/13691042.html