题目描述

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

输入

输入第一行一个正整数T,表示测试数据组数。

对于每组数据,
第一行两个正整数n;m;
第二行n个非负整数w1,w2...wn;
第三行n个正整数c1,c2...cn;
第四行n个正整数d1,d2...dn;
接下来n-1行每行两个正整数u;v表示u和v之间有一条道路
$n\le 500,m\le 4000$ 

输出

输出共T 行,每行一个整数,表示最大的喜爱度之和。

样例输入

1
3 2
1 2 3
1 1 1
1 2 1
1 2
1 3

样例输出

4


题解

树的点分治+dfs序+背包dp

终于get到了树形背包dp的正确姿势 = =

如果要求必须选 $x$ ,即做以 $x$ 为根的树形背包dp。

那么对于一个点,有两种情况:选和不选。

选的话即可选子节点,不选的话就不能选子树内的点。

因此使用dfs序进行dp。以 $x$ 为根进行dfs。设 $f[i][j]$ 表示使用dfs序上 $[i,n]$ 位置对应的节点,背包容量为 $j$ 时的最大重量。

对于位置 $i$ ,如果选,则从 $f[i+1][]$ 转移过来;否则子树内节点都不能选,从 $f[last[val[i]]+1][]$ 转移过来 。其中 $val[i]$ 表示dfs序上位置 $i$ 对应的节点编号,$last[i]$ 表示 $i$ 子树在dfs序上的区间右端点位置。

这样从后向前进行多重背包dp,最终的 $f[1][m]$ 即为以 $x$ 为根的树形背包dp的答案。

但是如果想本题这样,求任意一个连通块的结果呢?使用点分治,求出包含重心的答案,递归不包含重心的答案即可。

时间复杂度 $O(nm\log d\log n)$ ,如果使用单调队列优化多重背包的话即可使时间复杂度去掉一个log。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 510
using namespace std;
int m , w[N] , c[N] , d[N] , head[N] , to[N << 1] , next[N << 1] , cnt , si[N] , ms[N] , sum , root , vis[N] , val[N] , last[N] , tot , f[N][4010] , ans;
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void getroot(int x , int fa)
{
int i;
si[x] = 1 , ms[x] = 0;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
getroot(to[i] , x) , si[x] += si[to[i]] , ms[x] = max(ms[x] , si[to[i]]);
ms[x] = max(ms[x] , sum - si[x]);
if(ms[x] < ms[root]) root = x;
}
void dfs(int x , int fa)
{
int i;
si[x] = 1 , val[++tot] = x;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
dfs(to[i] , x) , si[x] += si[to[i]];
last[x] = tot;
}
void solve(int x)
{
int i , j , k , t;
vis[x] = 1 , tot = 0 , dfs(x , 0);
for(i = 1 ; i <= tot + 1 ; i ++ )
for(j = 0 ; j <= m ; j ++ )
f[i][j] = 0;
for(i = tot ; i ; i -- )
{
t = d[val[i]] - 1;
for(j = m ; j >= c[val[i]] ; j -- ) f[i][j] = f[i + 1][j - c[val[i]]] + w[val[i]];
for(j = 1 ; j <= t ; t -= j , j <<= 1)
for(k = m ; k >= j * c[val[i]] ; k -- )
f[i][k] = max(f[i][k] , f[i][k - j * c[val[i]]] + j * w[val[i]]);
if(t)
for(j = m ; j >= t * c[val[i]] ; j -- )
f[i][j] = max(f[i][j] , f[i][j - t * c[val[i]]] + t * w[val[i]]);
for(j = m ; ~j ; j -- ) f[i][j] = max(f[i][j] , f[last[val[i]] + 1][j]);
}
ans = max(ans , f[1][m]);
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]])
sum = si[to[i]] , root = 0 , getroot(to[i] , 0) , solve(root);
}
int main()
{
int T;
scanf("%d" , &T);
while(T -- )
{
memset(head , 0 , sizeof(head)) , cnt = 0;
memset(vis , 0 , sizeof(vis)) , ans = 0;
int n , i , x , y;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &w[i]);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &c[i]);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &d[i]);
for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
sum = n , ms[0] = 1 << 30 , root = 0 , getroot(1 , 0) , solve(root);
printf("%d\n" , ans);
}
return 0;
}

【bzoj4182】Shopping 树的点分治+dfs序+背包dp的更多相关文章

  1. Codeforces Round #200 (Div. 1) D Water Tree 树链剖分 or dfs序

    Water Tree 给出一棵树,有三种操作: 1 x:把以x为子树的节点全部置为1 2 x:把x以及他的所有祖先全部置为0 3 x:询问节点x的值 分析: 昨晚看完题,马上想到直接树链剖分,在记录时 ...

  2. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  3. 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  4. BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)

    题目大意: Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  5. [JSOI2016]最佳团体 DFS序/树形DP

    题目 洛谷 P4322 [JSOI2016]最佳团体 Description 茜茜的舞蹈团队一共有\(N\)名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,茜茜的编号是\(0\)号.每个候 ...

  6. BZOJ 4285 使者 (CDQ分治+dfs序)

    题目传送门 题目大意:给你一棵树,有三种操作,在两个点之间连一个传送门,拆毁一个已有的传送门,询问两个点之间的合法路径数量.一条合法路径满足 1.经过且仅经过一个传送门 2.不经过起点终点简单路径上的 ...

  7. 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...

  8. 【BZOJ】2819: Nim(树链剖分 / lca+dfs序+树状数组)

    题目 传送门:QWQ 分析 先敲了个树链剖分,发现无法AC(其实是自己弱,懒得debug.手写栈) 然后去学了学正解 核心挺好理解的,$ query(a) $是$ a $到根的异或和. 答案就是$ l ...

  9. 树的遍历顺序 - dfs序|欧拉序|dfn序(备忘)

    (仅作备忘) dfs序是dfs过程中对于某节点进入这个节点的子树和离开子树的顺序 满足每个节点都会在dfs序上出现恰好两次 任意子树的dfs序都是连续的 欧拉序是dfs过程中经过节点的顺序 每个节点至 ...

随机推荐

  1. [2016北京集训试题8]连在一起的幻想乡[dp+无向图计数]

    Description Solution 本博客参考yww大佬的博客,为了加深理解我就自己再写一遍啦. 以下的“无向图”均无重边无自环. 定义f0[n]为n个点构成的无向图个数,f1[n]为n个点构成 ...

  2. [BZOJ1185][HNOI2007]最小矩形覆盖-[凸包+旋转卡壳]

    Description 传送门 Solution 感性理解一下,最小矩形一定是由一条边和凸包上的边重合的. 然后它就是模板题了..然而真的好难调,小于大于动不动就打错. Code #include&l ...

  3. CF 868 F. Yet Another Minimization Problem

    F. Yet Another Minimization Problem http://codeforces.com/contest/868/problem/F 题意: 给定一个长度为n的序列.你需要将 ...

  4. kyligence enterprise3.2.x版本使用mysql作为数据源构建报错

    1.报错信息如下: exe cmd:null/bin/sqoop import -Dorg.apache.sqoop.splitter.allow_text_splitter=true -Dfs.de ...

  5. datax源代码编译安装

    what is DataX ? DataX是阿里巴巴集团内被广泛使用的离线数据同步工具/平台. 实现包括MySQL,SQL Server,Oracle,PostgreSQL,HDFS,Hive,HBa ...

  6. js创建对象 object.create()用法

    Object.create()方法是ECMAScript 5中新增的方法,这个方法用于创建一个新对象.被创建的对象继承另一个对象的原型,在创建新对象时可以指定一些属性. 语法: Object.crea ...

  7. 虚拟货币——比特币行情价格分析

    最近挖以太币的朋友们在关注以太坊行情时,一定会发现以太币的价格对比之前上涨了不少.肯定有部分朋友想了解这次上涨的原因,我们特地为此查询了一番.因为比特币相当于虚拟货币中的黄金,它的价格波动会波及到其他 ...

  8. ubuntu10.10安装使用vnc

    原文发表于:2010-12-15转载至cu于:2012-07-21 搭安全试验的环境,在vmware上安装了ubuntu10.10(大学的时候用过,最早用的好像是6系列吧).安装好后想用远程桌面控制, ...

  9. eclipse技巧-快捷键

    ctrl + 1,快速修复 ctrl + d, 快捷删除行 shift + Enter,快速移动光标到下一行 ctrl + F11,运行代码 alt + ↑/↓,快速移动行 ctrl + alt + ...

  10. Phonegap 环境配置

    目前要开发 Web App 还是有比较多的选择的 如 Phonegap.MUI.AppCan,接下来以 Web前端开发工程师 的角度来一个 Phonegap 的 First Blood 一.开发环境: ...