欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[JZOJ4202] Shopping

程序员文章站 2024-03-17 09:05:16
...

Description

[JZOJ4202] Shopping
[JZOJ4202] Shopping

Solution

简化题意就是选择一个树上的联通块,这个联通块中所有商店至少买一个做背包

树上联通块问题往往可以通过点分治转化成树形依赖问题

先对于整棵树点分治,每个分治中心分别作为当前分治子树的根来树形依赖背包就可以了

多重背包可以拆分成log个独立的物品来考虑
好像还有一种单调队列的做法可以省掉这个log?

复杂度O(NMlognlogd)
只要不是写的太丑基本上都能通过

Code

#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 505
#define R 4005
#define LL long long
using namespace std;
int n,m,t,w[N],m1,c[N],r[N],nt[2*N],dt[2*N],fs[N],f[N][R],g[R],ans,sz[N],mi,mw,dfn[N],vl[N][20],h[R];
bool bz[N];
void link(int x,int y)
{
    nt[++m1]=fs[x];
    dt[fs[x]=m1]=y;
}
void find(int k,int fa,int num)
{
    sz[k]=1;
    int mx=0;
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(p!=fa&&!bz[p])
        {
            find(p,k,num);
            sz[k]+=sz[p];
            mx=max(mx,sz[p]);
        }
    }
    if(max(mx,num-sz[k])<mi) mw=k,mi=max(mx,num-sz[k]);
}
void dfs(int k,int fa)
{
    sz[k]=1;
    dfn[++dfn[0]]=k;
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(p!=fa&&!bz[p])
        {
            dfs(p,k);
            sz[k]+=sz[p];
        }
    }
}
void doit(int k,int num)
{
    bz[k]=1;
    dfn[0]=0;
    dfs(k,0);
    fo(i,1,dfn[0]+1) fo(j,0,m) f[i][j]=0;  
    fod(i,dfn[0],1)
    {
        int p=dfn[i];
        fo(j,0,m) g[j]=f[i+1][j],h[j]=0;
        fo(x,1,vl[p][0])
        {   
            fod(j,m,vl[p][x]*c[p])
            { 
                h[j]=max(h[j],g[j-vl[p][x]*c[p]]+vl[p][x]*w[p]);
                g[j]=max(g[j],h[j]);
            }
        }
        fo(j,1,m) f[i][j]=max(f[i][j-1],max(h[j],f[i+sz[p]][j]));
    }
    ans=max(ans,f[1][m]);
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(!bz[p])
        {
            mi=num;
            find(p,k,sz[p]);
            doit(mw,sz[p]);
        }
    }
}
int main()
{
    cin>>t;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        fo(i,1,n) scanf("%d",&w[i]);
        fo(i,1,n) scanf("%d",&c[i]);
        memset(vl,0,sizeof(vl));
        fo(i,1,n) 
        {
            scanf("%d",&r[i]);
            int l=r[i];
            vl[i][0]=1,vl[i][1]=1,l--;
            while(l>=vl[i][vl[i][0]]*2)
            {
                vl[i][++vl[i][0]]=vl[i][vl[i][0]-1]*2;
                l-=vl[i][vl[i][0]];
            }
            if(l) vl[i][++vl[i][0]]=l;
            sort(vl[i]+1,vl[i]+vl[i][0]+1);
        }
        ans=0;
        m1=0;
        memset(bz,0,sizeof(bz));
        memset(nt,0,sizeof(nt));
        memset(fs,0,sizeof(fs));
        fo(i,1,n-1)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            link(x,y);
            link(y,x);
        }
        memset(f,0,sizeof(f));
        mi=n;
        find(1,0,n);
        doit(1,n);
        printf("%d\n",ans);
    }
}