【HDU5932 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 K】【树上背包 贪心乱搞】Backpack on Tree 物品成本只有12345下的树上背包
来源:互联网 发布:我知主掌管明天 编辑:程序博客网 时间:2024/04/26 17:54
Backpack on Tree
Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 43 Accepted Submission(s): 14
Problem Description
There is a rooted tree with n nodes. For each node i, there is an item whose volume is ci and value is vi and if node i is not the root, it is guaranteed that |subtreei|≤23|subtreefatheri| .Bacon wants to pick items in subtrees so that their total volume is exactly t. Help Bacon determine the maximal total value of items he can pick.
Input
The first line contains one integer T(1≤T≤40 ) and there are exactly T test cases below.
For each test case, the first line contains one integer n (1≤n≤2×104 ).
The following n - 1 lines describe edges in the tree. Each line contains two integersai and bi(1≤ai,bi≤n,ai≠bi) describing an edge of the tree.
For the following n lines, the i-th line contains two integersci and vi(1≤ci≤5,1≤vi≤109) .
Next line contains one integer the number of queries Q and each of the following Q lines contains two integerssi and ti(1≤si≤n,1≤ti≤105) as a query.
Note that node 1 is the root of the tree.
There is no more than 4 test cases that n is greater than104 , and no more than 10 test cases that n is greater than 103 . sum of all Q are not greater than 2×105 .
For each test case, the first line contains one integer n (
The following n - 1 lines describe edges in the tree. Each line contains two integers
For the following n lines, the i-th line contains two integers
Next line contains one integer the number of queries Q and each of the following Q lines contains two integers
Note that node 1 is the root of the tree.
There is no more than 4 test cases that n is greater than
Output
For each test case, first line contains "Case #x:", where x indicates the number of test cases (starting from 1).
Then print Q lines and the i-th line contains the answer of the i-th query. Print -1 for the query if there is no way to pick items insubtrees with total volume t.
Then print Q lines and the i-th line contains the answer of the i-th query. Print -1 for the query if there is no way to pick items in
Sample Input
251 21 31 41 51 12 23 34 45 531 152 23 351 21 31 44 55 1233 45434 211 12312 1231 55 24 4
Sample Output
Case #i:1523Case #2:455512-1HintThe tree in first case looks like the picture above,For query subtree_s =1,t= 15,we should pick items in subtree 1. only method is to pick allitems in subtree 1 and get value 15.
Source
2016CCPC东北地区大学生程序设计竞赛 - 重现赛
#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<ctype.h>#include<math.h>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }#define MS(x,y) memset(x,y,sizeof(x))#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }const int N = 2e4 + 10, Z = 1e9 + 7;template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int casenum, casei;int n, m;struct Edge{int w, nxt;}edge[N << 1]; int first[N], id;struct A{int c, v;bool operator < (const A&b)const{return (LL)v * b.c > (LL)b.v * c;}}a[N];vector<A>b[N];vector< pair<int,int> >q[N];int sumc[N];LL sumv[N];const int M = 60;const LL MX = 0x7f7f7f7f7f7f7f7f;const LL MN = 0xbfbfbfbfbfbfbfbf;LL mn[N][M];//mn[i]表示空间容量为i条件下最大收益LL mx[N][M];//mx[i]表示空间容量为i条件下最小收益LL ans[(int)1e5 + 10];int SZ;int find(int m){int l = 0;int r = SZ - 1;while (l < r){int mid = (l + r + 1) >> 1;if (sumc[mid] <= m)l = mid;else r = mid - 1;}return l;}void ins(int x, int y){edge[++id] = { y,first[x] };first[x] = id;}void dfs(int x, int fa){b[x].clear(); b[x].push_back(a[x]);for (int z = first[x]; z; z = edge[z].nxt){int y = edge[z].w;if (y == fa)continue;dfs(y, x);b[x].insert(b[x].end(),b[y].begin(), b[y].end());b[y].clear();}sort(b[x].begin(), b[x].end());int g = SZ = b[x].size();for (int i = 0; i < g; ++i){sumc[i] = b[x][i].c; if (i)sumc[i] += sumc[i - 1];sumv[i] = b[x][i].v; if (i)sumv[i] += sumv[i - 1];}for (int i = 0; i < g; ++i){for (int j = 0; j < M; ++j){mn[i][j] = MX;mx[i][j] = MN;}}//性价比最小的更新要从前缀取得if (!q[x].size())return;for (int i = 0; i < g; ++i){mn[i][0] = 0;mn[i][b[x][i].c] = b[x][i].v;if (i > 0)for (int j = 0; j < M; ++j){gmin(mn[i][j], mn[i - 1][j]);if (j >= b[x][i].c) gmin(mn[i][j], mn[i - 1][j - b[x][i].c] + b[x][i].v);}}//性价比最大的更新要从后缀取得for (int i = g - 1; i >= 0; --i){mx[i][0] = 0;mx[i][b[x][i].c] = b[x][i].v;if(i < g - 1)for (int j = 0; j < M; ++j){gmax(mx[i][j], mx[i + 1][j]);if (j >= b[x][i].c) gmax(mx[i][j], mx[i + 1][j - b[x][i].c] + b[x][i].v);}}for (auto it : q[x]){int o = it.first;int m = it.second;ans[o] = -1;if (m > sumc[g - 1]) continue;if (m < sumc[0]) { gmax(ans[o], mx[0][m]); continue; }int p = find(m);if (m == sumc[p]) { ans[o] = sumv[p]; continue; }//sumc[p] <= m <= sumc[p + 1]int add = m - sumc[p];for (int i = 0; i + add < M; ++i)if (mn[p][i] <= 1e9 && mx[p + 1][i + add] >= 0)gmax(ans[o], sumv[p] - mn[p][i] + mx[p + 1][i + add]);}}int main(){scanf("%d", &casenum);for (casei = 1; casei <= casenum; ++casei){scanf("%d", &n);for (int i = 1; i <= n; ++i){first[i] = 0;q[i].clear();}id = 1;for (int i = 1; i < n; ++i){int x, y; scanf("%d%d", &x, &y);ins(x, y); ins(y, x);}for (int i = 1; i <= n; ++i){scanf("%d%d", &a[i].c, &a[i].v);}scanf("%d", &m);for (int i = 1; i <= m; ++i){int x, y; scanf("%d%d", &x, &y);q[x].push_back({ i, y });}dfs(1, 0);printf("Case #%d:\n", casei);for (int i = 1; i <= m; ++i)printf("%lld\n", ans[i]);}return 0;}/*【trick&&吐槽】1,mx[x][0]和mx[x][0]要设置为02,我们更新答案的时候,一定要详细考虑边界答案的影响3,v的值不会爆int,但是v*c的值却会爆int,一定要小心!【题意】给你一棵有n(2e4)个节点的树对于节点i拥有成本c[i](1~5)和价值v[i](1~1e9)如果节点i不是根,则该节点子树的大小一定比父节点子树大小的2/3要小(也就是说树的深度不会很深)有q(2e5)个询问对于每个询问,给定子树根节点X和总成本大小C(1e5)我们要在子树X中找到总成本之和恰好为C的价值之和最大的物品,输出这个价值【类型】贪心 背包 乱搞【分析】本题的特殊点之处有1,深度不深,大概只有26~27层about2,物品成本很小,只有[1~5],但是背包容量却很大,可达1e5思考——1,我们可以把询问离线化。然后dfs,对于每棵树,便可以该棵树在某个容量下所对应的最优匹配答案2,背包如果做暴力的背包,复杂度是物品数*背包容量,复杂度是吃不消的不过因为物品的体积只有{1,2,3,4,5}所以如果背包的容量很大我们可以考虑一开始贪心性价比最高的然后对于最后的差值,我们去把这个差值弥补掉。如何维护这个差值呢?我们维护在每个点之前的空间容量为j的条件下最小的收益,我们可以考虑在其基础上剔除我们维护在每个点之后的空间容量为j的条件下最高的收益,我们可以考虑再起基础上增加这样我们得到sumc[p] <= m <= sumc[p + 1],定义add=m-sumc[p]我们可以考虑去在[0~p]中-(w),在[p+1~g)中再+(w+add)实现在这个条件下,就使得我们可以达到最优值。M的上限设置为60比较保险,但是设置小了也可以AC =w=【时间复杂度&&优化】树的深度不超过30节点数为n,每次DP的复杂度为n * M总复杂度为O(30 * n * M)可以控制在百万级别【数据】10051 21 31 44 55 1233 45434 211 12312 1211 5*/
0 0
- 【HDU5932 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 K】【树上背包 贪心乱搞】Backpack on Tree 物品成本只有12345下的树上背包
- 【HDU5931 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 J】【线性规划 乱搞】Mission Possible 购买护甲和回复力和速度使得最小成本穿越D距离
- 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 部分题解
- HDU Minimum’s Revenge 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU Mr. Frog’s Problem 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU Mr. Frog’s Game 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU Basic Data Structure 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- 【HDU5922 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 A】【水题】Minimum’s Revenge
- 【HDU5924 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 C】【水题】Mr. Frog’s Problem
- 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 D Coconuts HDU 5925
- 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 A - Minimum’s Revenge HDU 5922
- (HDU 5926)Mr. Frog’s Game 水题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- (HDU 5927)Auxiliary Set 思维题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- 2016CCPC东北地区大学生程序设计竞赛
- 2016CCPC东北地区大学生程序设计竞赛
- 【HDU5926 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 E】【水题】Mr. Frog’s Game 连连看
- HDU 5922 Minimum’s Revenge(思维题)——2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU 5926 Mr. Frog’s Game(连连看,暴力)——2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- 修改vmware虚拟机的虚拟磁盘卷标
- 设计模式之单例模式
- java 双重检测
- android手机无法用adb connect 10.58.106.158 指令
- 遍历map的几种方法
- 【HDU5932 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 K】【树上背包 贪心乱搞】Backpack on Tree 物品成本只有12345下的树上背包
- 做朋友圈的界面 cell的高度的动态调节2
- 求最小公倍数
- 【37.68%】【hdu 5918】Sequence I
- AllAngleExpandableButton
- display:flex 布局教程
- java代码实现二叉树的遍历
- Python 数据处理扩展包: pandas 模块的DataFrame介绍(创建和基本操作)
- 58. Length of Last Word