题目大意:给你一颗树,你有$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. 纯css3实现箭头、关闭按钮旋转效果

    说起css3的旋转效果,那就要说为什么不用js去实现,CSS3的动画效果,能够减少对JavaScript和Flash文件的HTTP请求这是原因之一.但是css3可能要求浏览器执行很多的工作来完成这个动 ...

  2. mybatis 批量导入数据到mysql返回批量Id

    1.首先mybatis版本必需是3.3.1或以上 2.mapper配置文件中 <insert id="insertOrderBatch" parameterType=&quo ...

  3. 《代码敲不队》第八次团队作业:Alpha冲刺 第三天

    项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 代码敲不队 作业学习目标 掌握软件编码实现的工程要求. 团队项目github仓库地址链接 GitH ...

  4. nyoj 38 简单并查集的应用&最小生成树

    #include<stdio.h> #include<stdlib.h> #define inf 0x3fffffff #define N 600 struct node { ...

  5. Python爬虫之正則表達式

    1.经常使用符号 .  :匹配随意字符,换行符 \n 除外 *  :匹配前一个字符0次或无限次 ? :匹配前一个字符0次或1次 .*  :贪心算法.尽可能的匹配多的字符 .*?  :非贪心算法 () ...

  6. 转载:手游安全破“黑”行动:向黑产业链说NO

    目前的手游市场已被称为红海.从业界认为的2013年的“手游元年”至今,手游发展可谓是既经历了市场的野蛮生长,也有百家争鸣的战国时代.如今,手游市场竞争已趋白热化,增长放缓.但移动互联网的发展大势之下, ...

  7. VS2010编译器工具cl对c++11标准支持情况測试

    本文探讨了VS2010编译工具cl对C++11标准的支持情况.提供了利用C++11新特性的两段代码来进行測试,并同g++ 4.9.3编译器的编译情况相对照.总的说来:VS2010的编译器工具cl部分支 ...

  8. CentOS6.5下安装远程桌面服务端软件VNC Server

    VNC 使您能够远程訪问和控制您的计算机从还有一计算机或移动设备上,不管你在世界的不论什么地方. 常见的使用情形,包含给同事和朋友提供桌面支持.远程管理您的服务器. 将 VNC Server部署到您想 ...

  9. hdoj 2795 Billboard 【线段树 单点更新 + 维护区间最大值】

    Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  10. Agile实践日志一 -- Grooming Session

    Agile实践日志一  -- Grooming Session GroomingSession 这个Session主要Go through我们下一个Sprint须要做的Story,大家都清楚之后,在每 ...