题目大意:给你一颗树,你有$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. Project Euler 42 Coded triangle numbers

    题意:三角形数序列的第n项由公式tn = 1/2n(n+1)给出:因此前十个三角形数是: 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, - 将一个单词的每个字母分别转化为其 ...

  2. P1828 香甜的黄油 Sweet Butter (spfa)

    题目描述 农夫John发现做出全威斯康辛州最甜的黄油的方法:糖.把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油.当然,他将付出额外的费 ...

  3. MySQL数据库唯一性设置(unique index)

    1,命令行操作 分为两种.一种是在建表时就想好要加上唯一性,另一种是在后期才发现需要设置唯一性. 建表时: CREATE TABLE `t_user` ( `Id` int(11) NOT NULL ...

  4. C# XML 反序列化解析

    自己用.记录一下! 用于配置文件的解析,可以用来设置配置.不用修改程序里参数. 用微软的XML 解析器来解析的. 1. Xml文件 文件名称:TestConfig.xml <?xml versi ...

  5. 监控Weblogic计数器

  6. Python的递归深度

    RuntimeError: maximum recursion depth exceeded while calling a Python object 大意是调用 Python 对象时超出最大深度限 ...

  7. POJ 2470 Ambiguous permutations(简单题 理解题意)

    [题目简述]:事实上就是依据题目描写叙述:A permutation of the integers 1 to n is an ordering of these integers. So the n ...

  8. UI各种小控件的用法

    今天给大家列举出来UI中的一些小控件的用法.方便大的学习与使用 一些方法和属性我们能够查看API文档.不必将每一个控件的功能都记住, 由于在使用的过程中,我们能够查看API文档.方便使用,我们仅仅要记 ...

  9. 浅谈cocos2dx(17) 中单例管理模式

    ----我的生活,我的点点滴滴!. 首先明白一个问题.什么是管理者模式,管理类是用来管理一组相关对象的类,他提供了訪问对象的接口,假设这么说比較抽象的话.我们来看下cocos2dx中都有哪些类是管理类 ...

  10. 创建cifs系统案例之“实现将Windows磁盘共享至Linux”

    原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong ...