hdu5932(贪心+树背包DP)

11 篇文章 0 订阅

题意:

给你一颗树,每个节点有一个v,一个w。
每次询问:i,T。
在节点i的子树中,恰好取∑v=T的一些节点,最大的w之和是多少?

可以说是非常牛逼的假题了。。假到现场竟然只有一人ac。。

由subtree[i]<=2/3subtree[fa[i]]可以得到,该树的高度不超过24(然后就懵逼了),然后就可以得知,所有节点的size和一定不超过20n(考虑单点贡献),所以可以直接用各种数据结构暴力维护所有子树节点

很容易想到用背包维护,但是复杂度真的太大了。。然而会发现一个很重要的信息就是,体积非常小,那么说明贪心策略是十分接近正解的,那可以先把性价比高的物品直接贪心地放下去,然后用背包把后几件物品去掉,再取接下来的几件物品做背包就可以了。。

可以说是十分乱搞了。。。

 

 

 

/**
 *          ┏┓    ┏┓
 *          ┏┛┗━━━━━━━┛┗━━━┓
 *          ┃       ┃  
 *          ┃   ━    ┃
 *          ┃ >   < ┃
 *          ┃       ┃
 *          ┃... ⌒ ...  ┃
 *          ┃              ┃
 *          ┗━┓          ┏━┛
 *          ┃          ┃ Code is far away from bug with the animal protecting          
 *          ┃          ┃   神兽保佑,代码无bug
 *          ┃          ┃           
 *          ┃          ┃        
 *          ┃          ┃
 *          ┃          ┃           
 *          ┃          ┗━━━┓
 *          ┃              ┣┓
 *          ┃              ┏┛
 *          ┗┓┓┏━━━━━━━━┳┓┏┛
 *           ┃┫┫       ┃┫┫
 *           ┗┻┛       ┗┻┛
 */ 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll  long long
#define eps 1e-12
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define NM 20005
#define nm 40005
#define pi 3.1415926535897931
const ll inf=1e16;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
 
 





struct edge{int t;edge*next;}e[nm],*h[NM],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
int n,_x,_y,a[NM],b[NM],cnt,l,r,ca,m,size[NM],vol;
ll dp[80];
vector<int>son[NM],c[NM];
vector<ll>d[NM];

bool cmp(int x,int y){return 1ll*b[x]*a[y]>1ll*b[y]*a[x];}

void dfs(int x,int f){
    size[x]=1;son[x].clear();son[x].push_back(x);c[x].clear();d[x].clear();
    link(x)if(j->t!=f){
	dfs(j->t,x);
	inc(k,0,size[j->t]-1)son[x].push_back(son[j->t][k]);
	size[x]+=size[j->t];
    }
    sort(son[x].begin(),son[x].end(),cmp);
    c[x].push_back(a[son[x][0]]);d[x].push_back(b[son[x][0]]);
    inc(k,1,size[x]-1)c[x].push_back(c[x][k-1]+a[son[x][k]]),d[x].push_back(d[x][k-1]+b[son[x][k]]);
}


int main(){
    //freopen("data.in","r",stdin);
    int _=read();while(_--){
	mem(e);mem(h);o=e;
	n=read();inc(i,2,n){_x=read();_y=read();add(_x,_y);add(_y,_x);}
	inc(i,1,n)a[i]=read(),b[i]=read();
	dfs(1,0);
	printf("Case #%d:\n",++ca);
	m=read();while(m--){
	    int x=read();_y=read();cnt=max(0,_y-70);
	    if(c[x][size[x]-1]<_y){printf("-1\n");continue;}
	    int t=lower_bound(c[x].begin(),c[x].end(),_y)-c[x].begin();
	    l=max(0,t-70);r=min(size[x]-1,t+70);
	    vol=c[x][t]-cnt;
	    dp[vol]=d[x][t];
	    inc(i,0,vol-1)dp[i]=-1;
	    inc(j,l,t)inc(k,0,vol-a[son[x][j]])if(dp[k+a[son[x][j]]]>=0)
		dp[k]=max(dp[k],dp[k+a[son[x][j]]]-b[son[x][j]]);
	    inc(j,t+1,r)dec(k,vol,a[son[x][j]])if(dp[k-a[son[x][j]]]>=0)
		dp[k]=max(dp[k],dp[k-a[son[x][j]]]+b[son[x][j]]);
	    if(dp[_y-cnt]>=0)printf("%lld\n",dp[_y-cnt]);else printf("-1\n");
	}
    }
    return 0;
}

 

 

 

 

 

 

Backpack on Tree

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


 

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,bin,aibi) 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≤sin,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东北地区大学生程序设计竞赛 - 重现赛

 

 

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6447 6446 6445 6444 6443 

 

 

Statistic | Submit | Discuss | Note

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值