题目大意:给你一颗树,你有$m$元钱,每个节点都有一种物品,价值为$w$,代价为$c$,有$d$个,如果在$u$和$v$两个城市都购买了至少一个物品,那么$u,v$路径上每个节点也都必须买至少一个物品

单调队列数组开小了调了2h

通过这道题,本蒟蒻终于$get$到了树上带权背包的正确姿势

合并背包的代价是$O(m^{2})$的,非常不友好,而在序列上处理背包时,是不需要合并背包的,所以我们把树拍成$dfs$序

显然,树上背包需要用子节点更新父节点的信息,所以倒序枚举时间戳$i$

设$f[i][j]$表示时间戳为$i$,总代价为$j$时,所有时间戳$>=i$的节点,树上背包能得到的最大价值,令$x$表示时间戳为$i$的节点编号

如果不选节点$x$,那么它子树内的节点都不能选,为了保证$f[i]$是$i$后面所有节点构成的最优解,所以跳过$x$子树的状态,用$f[ed_{x}+1]$更新$f[i]$,$ed_{x}$表示节点$x$的出栈时间

如果选节点$x$,那么可以选$x$的子树内的节点,用$f[i+1]$更新$f[i]$

两者取最优解即可

树上带权$01$背包的时间被我们优化成了$O(nm)$

多重背包可以用单调队列优化,时间一样是$O(nm)$

而上面的$dp$方程仅适用于必须链并经过根节点的情况

所以使用点分治每次选择一个重心作为根跑$DP$

总时间$O(Tnmlogn)$

代码巨丑

 #include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 510
#define M1 4010
#define ll long long
#define inf 233333333
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,K,T;
struct Edge{
int to[M1],nxt[M1],head[N1],cte;
void ae(int u,int v)
{cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;}
}E; int W[N1],C[N1],D[N1];
int st[N1],ed[N1],id[N1],tot;
int sz[N1],lim[N1];
int use[N1],mi,G;
void gra(int u,int dad,int szfa)
{
int j,v,ma=szfa;
if(szfa>mi) return;
for(j=E.head[u];j;j=E.nxt[j])
{
v=E.to[j]; if(use[v]||v==dad) continue;
ma=max(ma,sz[v]);
gra(v,u,szfa+sz[u]-sz[v]);
}
if(ma<mi) mi=ma,G=u;
}
void dfs_pre(int u,int dad)
{
int j,v; sz[u]=;
st[u]=++tot; id[tot]=u;
for(j=E.head[u];j;j=E.nxt[j])
{
v=E.to[j]; if(use[v]||v==dad) continue;
lim[v]=lim[u]-C[u];
dfs_pre(v,u); sz[u]+=sz[v];
}
sz[u]++; ed[u]=tot;
}
int que[M1],hd,tl;
int f[N1][M1],ans,de;
void calc(int u)
{
int i,j,k,p,x,w,d,c;
memset(f[tot+],,sizeof(f[tot+]));
for(i=tot;i;i--)
{
x=id[i]; c=C[x]; d=D[x]; w=W[x];
memcpy(f[i],f[ed[x]+],sizeof(f[i]));
for(j=;j<c;j++)
{
hd=,tl=,que[++tl]=;
for(k=;k*c+j<=lim[x];k++)
{
while(hd<=tl&&k-que[hd]>d)
hd++;
f[i][k*c+j]=max(f[i][k*c+j],f[i+][que[hd]*c+j]+(k-que[hd])*w);
while(hd<=tl&&f[i+][k*c+j]-k*w>=f[i+][que[tl]*c+j]-que[tl]*w)
tl--;
que[++tl]=k;
}
}
}
for(j=;j<=K;j++) ans=max(ans,f[][j]);
}
void main_dfs(int u)
{
int j,v;
use[u]=; tot=,lim[u]=K;
dfs_pre(u,-);
calc(u);
for(j=E.head[u];j;j=E.nxt[j])
{
v=E.to[j]; if(use[v]) continue;
mi=inf,G=,gra(v,u,);
main_dfs(G);
}
}
void MAIN()
{
dfs_pre(,-);
mi=inf,G=,gra(,-,);
main_dfs(G);
}
void init()
{
tot=,E.cte=,ans=;
memset(use,,sizeof(use));
memset(E.head,,sizeof(E.head));
} int main()
{
freopen("t2.in","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&K);
int i,x,y,z; init();
for(i=;i<=n;i++) W[i]=gint();
for(i=;i<=n;i++) C[i]=gint();
for(i=;i<=n;i++) D[i]=gint();
for(i=;i<n;i++)
{
x=gint(), y=gint();
E.ae(x,y),E.ae(y,x);
}
MAIN();
printf("%d\n",ans);
}
return ;
}

BZOJ 4182 Shopping (点分治+树上多重背包)的更多相关文章

  1. [BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化)

    [BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化) 题面 马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街.商店街有n个商店,并且它们之间的道路构成了一颗树 ...

  2. BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)

    BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...

  3. [Bzoj4182]Shopping(点分治)(树上背包)(单调队列优化多重背包)

    4182: Shopping Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 374  Solved: 130[Submit][Status][Disc ...

  4. bzoj4182 Shopping 点分治+单调队列优化多重背包

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4182 题解 有一个很直观的想法是设 \(dp[x][i]\) 表示在以 \(x\) 为根的子树 ...

  5. bzoj4182/luoguP6326 Shopping(点分治,树上背包)

    bzoj4182/luoguP6326 Shopping(点分治,树上背包) bzoj它爆炸了. luogu 题解时间 如果直接暴力背包,转移复杂度是 $ m^{2} $ . 考虑改成点分治. 那么问 ...

  6. BZOJ4182: Shopping(点分治,树上背包)

    Description 马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街.商店街有n个商店,并且它们之间的道路构成了一颗树的形状. 第i个商店只卖第i种物品,小苗对于这种物品的喜爱度 ...

  7. BZOJ.3425.[POI2013]Polarization(DP 多重背包 二进制优化)

    BZOJ 洛谷 最小可到达点对数自然是把一条路径上的边不断反向,也就是黑白染色后都由黑点指向白点.这样答案就是\(n-1\). 最大可到达点对数,容易想到找一个点\(a\),然后将其子树分为两部分\( ...

  8. BZOJ 4753 [Jsoi2016]最佳团体 | 树上背包 分数规划

    BZOJ 4753 [Jsoi2016]最佳团体 | 树上背包 分数规划 又是一道卡精度卡得我头皮发麻的题-- 题面(--蜜汁改编版) YL大哥是24OI的大哥,有一天,他想要从\(N\)个候选人中选 ...

  9. 【bzoj4182】Shopping 树的点分治+dfs序+背包dp

    题目描述 给出一棵 $n$ 个点的树,每个点有物品重量 $w$ .体积 $c$ 和数目 $d$ .要求选出一个连通子图,使得总体积不超过背包容量 $m$ ,且总重量最大.求这个最大总重量. 输入 输入 ...

随机推荐

  1. webpack学习笔记(3)--webpack.config.js

    module 参数 使用下面的实例来说明 module.exports = { module: { rules: [ { test: /\.css$/, use: 'css-loader' }, { ...

  2. [Libre 6281] 数列分块入门 5 (分块)

    水一道入门分块qwq 题面:传送门 开方基本暴力.. 如果某一个区间全部都开成1或0就打上标记全部跳过就行了 因为一个数开上个四五六次就是1了所以复杂度能过233~ code: //By Menteu ...

  3. linux一些简单的操作命令

    命令ifconfig -a——查询自己ip地址命令top——查看cpu.内存命令uname——查看系统版本命令pwd——查看当前路径命令ln——建立连接 ln source_path target_p ...

  4. Swoole 源码分析——基础模块之 Pipe 管道

    前言 管道是进程间通信 IPC 的最基础的方式,管道有两种类型:命名管道和匿名管道,匿名管道专门用于具有血缘关系的进程之间,完成数据传递,命名管道可以用于任何两个进程之间.swoole 中的管道都是匿 ...

  5. crontab 设置定时任务

    查看当前用户已有的定时任务: crontab -l 编辑crontab: crontab -e 加入需要执行的命令: 0 */4 * * * /www/shwww.net/venv/bin/pytho ...

  6. 在windows环境中关于 pycharm配置 anaconda 虚拟环境

    因为要在windows系统系统中练习tensorflow,所以需要配置一下环境(来回的开关机切换环境太麻烦了......) 首先安装anaconda3,我选择的版本是Anaconda3 5.1.0,对 ...

  7. C++调用C#编写的DLL【转】

    1.打开VS新建项目 2.在新建项目窗口中选择其他语言->Visual C++->Win 32控制台应用程序,设置名称:MathCon,设置解决方案名:MathCon,这个名字随便你自己取 ...

  8. CodeForcesGym 100548G The Problem to Slow Down You

    The Problem to Slow Down You Time Limit: 20000ms Memory Limit: 524288KB This problem will be judged ...

  9. NYIST 1083 美丽的校园

    美丽的校园时间限制:1000 ms | 内存限制:65535 KB难度:3 描述 美丽的校园需要大家维护,作为南工学子,当然有责任! 在计科系门前有n棵树,按一行排列在计科系楼前面,它们在一条直线上, ...

  10. oracle导入expdp、导出impdp数据库用户

    仅限oracle服务器上执行:把172.16.251.136:1521/orcl的AMI4_2用户导入到192.168.2.30:1521/orclss中的AMI1用户:  关于导入导出更详细的见文章 ...