题目大意:给你一颗树,你有$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. iframe嵌入的子页面如何刷新父窗口

    iframe中刷新父页面方法及一些按钮刷新代码集合[原创+转]2009-07-23 11:12a页面里iframe了个b页面,我想实现在b页面里一个按钮,一按就刷新a页面,也就是父页面,不是只刷新if ...

  2. 【LibreOJ 6280】 数列分块入门 4 (分块)

    题目:传送门 听说用define会使代码简洁qwq code: //By Menteur_Hxy #include<cstdio> #include<iostream> #in ...

  3. XPath语法简明介绍

    简介: XPath 是一门在 XML 文档中查找信息的语言.XPath 用于在 XML 文档中通过元素和属性进行导航. XPath 路径表达式: XPath 使用路径表达式来选取 XML 文档中的节点 ...

  4. 谈谈python里面关于任务队列

    谈谈python里面关于任务队列 为什么要做任务队列 要回答这个问题我们首先看看在流水线上的案列,如果人的速度很慢,机器的速度比人的速度快很多,就会造成,机器生产的东西没有及时处理,越积越多,造成阻塞 ...

  5. LVM实践

    [root@ftp:/root] > fdisk -l Disk /dev/sda: 53.7 GB, 53687091200 bytes, 104857600 sectors Units = ...

  6. String 基本使用方法, 以及要注意的事项

    package chengbaoDemo; public class Test01 { public static void main(String[] args) { //字符串的两种创建形式 St ...

  7. eclipse svn -- - --- appears to be part of a subversion 1.7 or greater....解决方法

    安装与svn1.7相兼容的flex Eclipse中的SVN(subclipse) 今天差点被TortoiseSVN1.7和subclipse弄崩溃... 还好最后弄好了,在此把方法写出来,以免其他人 ...

  8. 使用动态代理实现dao接口

    使用动态代理实现dao接口的实现类 MyBatis允许只声明一个dao接口,而无需写dao实现类的方式实现数据库操作.前提是必须保证Mapper文件中的<mapper>标签的namespa ...

  9. warning:deprecated conversion from string constant to &#39;char *&#39;

    warning:deprecated conversion from string constant to 'char *' 解决方式 #include <iostream> using ...

  10. spark视频教程免费下载

    下载地址:点我下载   其它章节陆续上传中,Hadoop视频教程正在整理中,敬请关注.