HDU-5932 Backpack on Tree(DP+贪心)

13 篇文章 0 订阅

Backpack on Tree

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 193    Accepted Submission(s): 54

 

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 integers  ai 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 integers ci 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 integers si 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 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

2 5 1 2 1 3 1 4 1 5 1 1 2 2 3 3 4 4 5 5 3 1 15 2 2 3 3 5 1 2 1 3 1 4 4 5 5 123 3 4543 4 21 1 1231 2 12 3 1 5 5 2 4 4

Sample Output

Case #i: 15 2 3 Case #2: 4555 12 -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 all items in subtree 1 and get value 15.

Source

2016CCPC东北地区大学生程序设计竞赛 - 重现赛

题意:树上每个点都有重量w[i]和权值val[i],有m次询问,每次查询以si为根节点的子树上节点重量和为ti的最大权值和为多少

题解:由于t最大为1e5不能直接用背包来做。考虑到每个点的重量为[1,5],我们可以先做一部分贪心,然后做DP

由于题目对于子树大小的限制,可以知道递归深度最多只有30层,可以用滚动数组记录子树的所有节点。

设a[u]和b[u]为以u为根的子树上所有点的重量和权值,按照a[u][i] / b[u][i]从大到小排序(即单位重量的权值)

从前往后维护一个取最小权值和的背包dp1[i][j](物品[1,i]重量恰好为j的最小权值)

从后往前维护一个取最大权值和的背包dp2[i][j](物品[i,sz]重量恰好为j的最大权值)

\sum_{i=1}^{x}b[u][i]\leq t,则有ans=max(ans,\sum_{i=1}^{x}val[i]-dp1[i][j]+dp2[i][j])

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define add(x,y) x=((x)+(y)>=mod)?(x)+(y)-mod:(x)+(y)
#define sub(x,y) x=((x)-(y)<0)?(x)-(y)+mod:(x)-(y)
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 1e5 + 5;

struct Edge {
    int v, nxt;
} E[MX];
int head[MX], tot;
void init(int n) {
    rep(i, 1, n + 1) head[i] = -1;
    tot = 0;
}
void edge_add(int u, int v) {
    E[tot] = (Edge) {v, head[u]}, head[u] = tot++;
}
VI a[60][6];
PII arr[MX];
vector<PII>ver[MX];
int w[MX], val[MX], last[6];

void merge(int dep) {
    rep(j, 1, 6) rep(k, 0, a[dep + 1][j].size()) {
        a[dep][j].push_back(a[dep + 1][j][k]);
    }
}
bool cmp(PII p1, PII p2) {
    return (ll)p1.x * p2.y > (ll)p2.x * p1.y;
}
const int ad = 15;
ll dp1[MX][20], dp2[MX][20];
void pre_solve(int dep, int& sz) {
    rep(j, 1, 6) if(!a[dep][j].empty()) sort(a[dep][j].begin(), a[dep][j].end());
    rep(j, 1, 6) rep(k, 0, a[dep][j].size()) {
        arr[sz++] = PII(a[dep][j][k], j);
    }
    sort(arr, arr + sz, cmp);
    rep(j, 1, 6) last[j] = a[dep][j].size();
    memset(dp1[0], 0x3f, sizeof(dp1[0]));
    memset(dp2[sz], -1, sizeof(dp2[sz]));
    dp1[0][0] = dp2[sz][0] = 0;
    rep(i, 0, sz) {
        memcpy(dp1[i + 1], dp1[i], sizeof(dp1[i]));
        per(j, ad, arr[i].y) if(dp1[i][j - arr[i].y] < INFLL) {
            dp1[i + 1][j] = min(dp1[i + 1][j], dp1[i][j - arr[i].y] + arr[i].x);
        }
    }
    per(i, sz, 0) {
        memcpy(dp2[i], dp2[i + 1], sizeof(dp2[i]));
        per(j, ad, arr[i].y) if(dp2[i + 1][j - arr[i].y] >= 0) {
            dp2[i][j] = max(dp2[i][j], dp2[i + 1][j - arr[i].y] + arr[i].x);
        }
    }
}
ll ans[2 * MX];
void dfs(int u, int dep, int pre) {
    rep(i, 1, 6) a[dep][i].clear();
    a[dep][w[u]].push_back(val[u]);
    for(int i = head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == pre) continue;
        dfs(v, dep + 1, u);
        merge(dep);
    }
    if(ver[u].empty()) return;
    int sz = 0; pre_solve(dep, sz);
    sort(ver[u].begin(), ver[u].end());
    int tot = 0, j = 0; ll sum = 0;
    rep(i, 0, ver[u].size()) {
        int x = ver[u][i].x, y = ver[u][i].y;
        while(j < sz && tot + arr[j].y <= x) {
            sum += arr[j].x, tot += arr[j].y;
            last[arr[j].y]--, j++;
        }
        ans[y] = -1;
        rep(k, 0, ad) if(dp1[j][k] >= 0 && dp2[j][x - tot + k] >= 0) {
            ans[y] = max(ans[y], sum - dp1[j][k] + dp2[j][x - tot + k]);
        }
    }
}

int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif // local
    int T, u, v, n, q; cin >> T;
    rep(cas, 1, T + 1) {
        printf("Case #%d:\n", cas);
        cin >> n; init(n);
        rep(i, 1, n) {
            scanf("%d%d", &u, &v);
            edge_add(u, v);
            edge_add(v, u);
        }
        rep(i, 1, n + 1) ver[i].clear();
        rep(i, 1, n + 1) scanf("%d%d", &w[i], &val[i]);
        cin >> q;
        rep(i, 1, q + 1) {
            scanf("%d%d", &u, &v);
            ver[u].push_back(PII(v, i));
        }
        dfs(1, 0, 1);
        rep(i, 1, q + 1) printf("%lld\n", ans[i]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值