1097: Gifts with different style
Time Limit: 1 Sec Memory Limit: 16 MBSUBMIT: 139 Solved: 38
[SUBMIT] [STATUS]
Description
前些日子GBQC国的小明在凤凰古城痛痛快快地玩了两天,临走之前希望给女友带回两件不同种类的纪念品,而且小明的背包最多只能容纳总体积不超过V的物品,各个纪念品使其女友的高兴程度的增加值也不全是一样的。
现在小明想知道,对于小明有有财力购买的N个纪念品,他需要买回哪两个才能使女友的高兴程度的增加值最大呢?
Input
输入包含多组测试数据。
对于每组测试数据,第一行包含三个整数N(1<=N<=10^5), C(1<=C<=10^4), V(1<=V<=10^4),其中N表示小明有财力购买的一共有N个纪念品,C表示市面上销售的纪念品一共可以分为C个种类,V表示小明的背包最多只能容纳体积不超过V的物品。接下来N行,每行用三个正整数i(1<=i<=C)、j(1<=j<=10^4)、k(1<=k<=10^5)描述一个可以购买的纪念品,表示这个纪念品属于第i个种类,其体积为j,如果将其买回可使女友的高兴程度增加k。
Output
对于每组测试数据,用一行输出一个整数表示小明最多可以让女友的高兴程度增加多少。如果小明没办法带回两件不同种类的纪念品,则输出“-1”(不包括引号)。
Sample Input
Sample Output
HINT
由于数据量较大,推荐使用scanf和printf。
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1097
一开始我按背包做 超时了 很多人说优化一下就可以过了 现在判题系统坏了 等好了以后一定要试试
思路 线段树:/*
按物品种类排序,将相同种类的物品与之前按体积放入线段树的范围为0~限制体积-当前物品
体积的区间物品进行匹配,更新最优解后将该类物品全部插入线段树(按更优价值更新)。
*/
下面是 同学的代码
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
struct node
{
int w,v;
};
struct tree
{
int l,r,M;
}btree[50000];
int Max(int a,int b){return a<b?b:a;}
void build(int i,int l,int r)
{
int mid;
btree[i].l=l;
btree[i].r=r;
btree[i].M=0;
if(l==r)
return;
mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
}
void update(int i,int p,int v)
{
btree[i].M=Max(btree[i].M,v);
if(btree[i].l<btree[i].r)
{
if(p<=btree[i<<1].r)
update(i<<1,p,v);
else update(i<<1|1,p,v);
}
}
int query(int i,int p)
{
if(btree[i].l==btree[i].r)
return btree[i].M;
else
{
if(p<=btree[i<<1].r)
return query(i<<1,p);
else return Max(btree[i<<1].M,query(i<<1|1,p));
}
}
int main()
{
int n,c,v,i,k,len,sum,t;
while(scanf("%d%d%d",&n,&c,&v)!=EOF)
{
vector<node> list[10010];
node tem;
for(i=0;i<n;i++)
{
scanf("%d%d%d",&k,&tem.w,&tem.v);
list[k].push_back(tem);
}
sum=-1;
build(1,1,v);
for(i=1;i<=c;i++)
{
len=list[i].size();
if(!len)continue;
for(k=0;k<len;k++)
{
if(v-list[i][k].w>0)
{
t=query(1,v-list[i][k].w);
if(t)sum=Max(sum,t+list[i][k].v);
}
}
for(k=0;k<len;k++)
if(list[i][k].w<=v)
update(1,list[i][k].w,list[i][k].v);
}
printf("%d\n",sum);
}
return 0;
}