【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(1T40) and there are exactly T test cases below.

For each test case, the first line contains one integer n (1n2×104).

The following n - 1 lines describe edges in the tree. Each line contains two integers  ai and bi(1ai,bin,aibi) describing an edge of the tree.

For the following n lines, the i-th line contains two integers ci and vi(1ci5,1vi109).

Next line contains one integer the number of queries Q and each of the following Q lines contains two integers si and ti(1sin,1ti105) 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 than 104, and no more than 10  test cases that n is greater than 103. sum of all Q are not greater than 2×105.
 

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 in subtrees with total volume t.
 

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-1
Hint
The 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
原创粉丝点击