E-希望(线段树加01背包)

链接:https://ac.nowcoder.com/acm/contest/917/E
来源:牛客网
 

题目描述

水宝宝驾驶着毁灭号接近了勇者号舰桥。

他要使用毁灭号的等离子炮摧毁勇者号主控台。

但是操控等离子炮的程序出了点问题。等离子炮有n个操作信号,第i个操作信号的强度为b[i]。总体强度为各操作信号的强度之和。

由于有些信号太弱了了 (强度<0),水宝宝想把它们删除。但是水宝宝自己不会删除信号,所以他找来了同船的队友帮忙。

有 m位队友,第ii 位队友只会删除编号在 L[i] 和 R[i]之间的信号,且每删除一个信号,花费 C[i]格能量。飞船一共有 k格能量,问他在请队友删除完信号后,总体强度最大是多少。

 

 

 

注:本系列题不按难度排序哦

 

输入描述:

输入格式:

第一行包含三个正整数 n,k,m

第二行包含 n个正整数 b1,b2,⋯,bn,表示各信号的强度。

接下来 m 行,每行三个正整数Li,Ri,Ci,表示一个队友的属性。

输出描述:

输出格式:

输出一行一个整数,表示最大的信号强度

示例1

输入

复制

5 10 5
10 -2 -5 7 -10
1 1 5
2 4 10
4 4 12
3 4 10
1 5 15

输出

复制

5

说明

样例解释:花费10的代价除掉a[3],答案即为10+7-10-2=5

备注:

对于 100% 的数据,1≤n,m≤10^5;1≤k≤500;1≤C[i]≤500;1≤L[i]≤R[i]≤n;-10^9≤b[i]≤10^9

这题不看区间更新那是不是很像一个01背包的做法。最小花费最大容量,我们只需要把负的去掉尽量多就可以了。

难就难在如何区间更新?细细一想其实可以联想到线段树的区间更新,需要懒人标记,无奈自己线段树水平太差,打了半个小时没写出来,第二天又花了半个小时才做出来。。。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10; 
const ll inf=1e18;
ll sum[N*4],w[N],dp[600];
int flag[N*4],v[N];

int n,k,m,cnt;	
struct node
{
	int x,id;
}a[N];
void build(int id,int l,int r)
{
	sum[id]=inf;
	flag[id]=1;
	if(l==r) return ;
	int mid=l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
}
void pushdown(int id,int l,int r)
{
	if(flag[id])
	{
		sum[id<<1]=min(sum[id<<1],sum[id]);
		sum[id<<1|1]=min(sum[id<<1|1],sum[id]);
	}
}
void up(int id,int l,int r,int ql,int qr,ll val)
{
	if(l==r) 
	{
		sum[id]=min(sum[id],val);
		flag[id]=1;
		return ;
	}
	if(ql<=l&&r<=qr)
	{
		if(flag[id])
		{
			sum[id]=min(sum[id],val);
			return ;
		}
	}
	pushdown(id,l,r);
	int mid=l+r>>1;
	if(ql<=mid) up(id<<1,l,mid,ql,qr,val);
	if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,val);
	if(sum[id<<1]!=inf&&sum[id<<1|1]!=inf&&sum[id<<1]==sum[id<<1|1]) flag[id]=1,sum[id]=sum[id<<1]; 
	else flag[id]=0,sum[id]=inf;	
}
ll qu(int id,int l,int r,int pos)
{
	if(l==r) return sum[id];
	if(flag[id]) return sum[id];
	pushdown(id,l,r);
	int mid=l+r>>1;
	if(pos<=mid) return qu(id<<1,l,mid,pos);
	else return qu(id<<1|1,mid+1,r,pos);
}
int main()
{
	cin>>n>>k>>m;
	build(1,1,n);
	ll sum=0;
	for(int i=1;i<=n;i++)
	{
		ll x;
		scanf("%lld",&x);
		sum+=x;
		if(x<0) a[++cnt].x=x,a[cnt].id=i;
	}
	for(int i=1;i<=m;++i)
	{
		int l,r,vv;
		scanf("%d%d%d",&l,&r,&vv);
		up(1,1,n,l,r,vv);
	}
	int inde=0;
	for(int i=1;i<=cnt;++i)
	{
		ll num=qu(1,1,n,a[i].id);
		if(num==1e9+10) continue;
		v[++inde]=-a[i].x;
		w[inde]=num;
	}
	for(int i=1;i<=inde;++i)
	for(int j=k;j-w[i]>=0;j--)
		dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	printf("%lld\n",sum+dp[k]);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙大学ccsu_deer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值