线段树(最小值)+01背包

/*
https://ac.nowcoder.com/acm/contest/917/E
题意:
离子炮有n个操作信号,第i个操作信号的强度为b[i]。总体强度为各操作信号的强度之和。
由于有些信号太弱了了 (强度<0)。 
有 m位队友,第i位队友只会删除编号在 L[i] 和 R[i]之间的信号,且每删除一个信号,
花费 C[i]格能量。飞船一共有 k格能量,问他在请队友删除完信号后,总体强度最大是多少。 

看到这种形式就应该想到往01背包上靠 

这题可以转换成01背包 把每个区间更新 线段树维护最小值 然后转换成01背包取最大值 
*/
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
const int inf=0x3f3f3f3f;
int tree[N<<2],lazy[N<<2];
int a[N],c[N];
long long sum,dp[N];
void build(int l,int r,int k)
{
	lazy[k]=inf;
	if(l==r){
		tree[k]=inf;
		return;
	} 
	int mid=(l+r)>>1;
	build(l,mid,k<<1);
	build(mid+1,r,k<<1|1);
	tree[k]=min(tree[k<<1],tree[k<<1|1]);
	
}
void push_down(int k)
{
	tree[k<<1]=min(tree[k<<1],lazy[k]);
	tree[k<<1|1]=min(tree[k<<1|1],lazy[k]);
	lazy[k<<1]=min(lazy[k<<1],lazy[k]);
	lazy[k<<1|1]=min(lazy[k<<1|1],lazy[k]);
	lazy[k]=inf; 
} 
void update(int x,int y,int z,int l,int r,int k)
{
	if(x<=l&&y>=r){
		tree[k]=min(tree[k],z);
		lazy[k]=min(lazy[k],z);
		return ;
	}
	push_down(k);
	int mid=(l+r)>>1;
	if(x<=mid) update(x,y,z,l,mid,k<<1);
	if(y>mid) update(x,y,z,mid+1,r,k<<1|1);
	tree[k]=min(tree[k<<1],tree[k<<1|1]); 
}
void dfs(int l,int r,int k)
{
	if(l==r){
		c[l]=tree[k];
		return;
	}
	push_down(k);
	int mid=(l+r)>>1;
	dfs(l,mid,k<<1);
	dfs(mid+1,r,k<<1|1);
}
int main()
{
	int n,k,m;
	scanf("%d %d %d",&n,&k,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i];
	build(1,n,1);
	for(int i=1;i<=m;i++){
		int l,r,x;
		scanf("%d %d %d",&l,&r,&x);
		update(l,r,x,1,n,1);
	}
	dfs(1,n,1);
	for(int i=1;i<=n;i++){
		if(a[i]<0){
			for(int j=k;j>=c[i];j--){
				dp[j]=max(dp[j],dp[j-c[i]]-a[i]);
			}
		}
	}
	printf("%lld\n",sum+dp[k]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值