题目描述
题目背景
那一瞬间,一道白光闪过,从此大地上再也没有了丝毫的响动
那是一个黑暗的晚上。
新纪元59β年,23:13:56,这个悲惨的时刻。
所有人都开始自相残杀,亲人、朋友,都是敌人。
终有人类逃出了这片黑暗的天地,试图挽救这悲惨的未来。
但是腐化生物的能力完全超出了人类的控制范围。
勇者号的主控台与舰桥,人类最后与腐化生物抗衡的希望。
很可惜,α计划失败了,腐化生物即将入侵主控台。人类的最后英雄试图反抗。
这一切都是徒劳。
不!还有最后的希望!毁灭号的等离子充能炮!
如果不能得到,就将他彻底毁掉。
新纪元596α,下起了倾盆大雨,哭诉着勇者号自豪去死的英雄。 题目描述
水宝宝驾驶着毁灭号接近了勇者号舰桥。
他要使用毁灭号的等离子炮摧毁勇者号主控台。
但是操控等离子炮的程序出了点问题。等离子炮有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≤105;1≤k≤500;1≤C[i]≤500;1≤L[i]≤R[i]≤n;-109≤b[i]≤10^9
新纪596α 12:00:14水宝宝用沾满汗水的双手拉动了操纵杆,将等离子炮对准了勇者号主控台。
“再见。勇士们。”水宝宝向勇者号发送了它能接收的最后一条信息。
水宝宝用微颤的手摁下了Enter。
一声巨响后,世界重归宁静。
英雄们倒在了炮火里,没有痛苦。
整个世界只剩毁灭号引擎的轰鸣。
如果失去了勇者号,我们只能孤注一掷。
人类最后的希望,R8IO核弹。
北半球的天空,从此只有黑夜。
首先分析题目对于每一个可能删除的信号就使用线段树来维护删除消耗的最小值,接着将删除的最小值消耗看做“重量”,信号(都为负值)的绝对值看做“价值”,那就是简单的01背包。
思维不难,就线段树有点难度吧。
#include"iostream"
#include"cstdio"
#include"algorithm"
#define maxn 1000000
#define INF 100000
using namespace std;
struct TreeNode{
int tag,l,r;
};
int v[100005],w[100005],a[100005];
long long dp[550],ans,sum = 0;
TreeNode Tree[maxn*4+5];
void build(int index,int L,int R){
Tree[index].l = L;
Tree[index].r = R;
Tree[index].tag = INF;
if(L==R)return;
int Mid = (L+R)/2;
build(index<<1,L,Mid);
build(index<<1|1,Mid+1,R);
}
void Down(int index){
Tree[index<<1].tag = min(Tree[index].tag,Tree[index<<1].tag);
Tree[index<<1|1].tag = min(Tree[index].tag,Tree[index<<1|1].tag);
}
void change(int index,int L,int R,int value){//区间修改
if(L<=Tree[index].l&&R>=Tree[index].r){
Tree[index].tag = min(Tree[index].tag,value);
return;
}
int Mid = (Tree[index].l + Tree[index].r)/2;
if(Mid >= L)change(index<<1,L,R,value);
if(Mid < R)change(index<<1|1,L,R,value);
}
void ask(int index,int x){//单点查询
if(Tree[index].l==Tree[index].r&&Tree[index].l==x){
ans = Tree[index].tag;
return;
}
Down(index);
int Mid = (Tree[index].l + Tree[index].r)/2;
if(Mid>=x)ask(index<<1,x);
else ask(index<<1|1,x);
}
int main(){
int N,M,cnt = 0,W;
scanf("%d%d%d",&N,&W,&M);
build(1,1,N);
for(int i = 1;i <= N;i++)
{scanf("%d",&a[i]);sum+=a[i];}
for(int i = 1;i <= M;i++){
int l1,r1;
int x;
scanf("%d%d%d",&l1,&r1,&x);
change(1,l1,r1,x);
}
for(int i = 1;i <= N;i++){
if(a[i]<0)v[cnt] = -a[i],ask(1,i),w[cnt] = ans,cnt++;
}
for(int i = 0;i < cnt;i++)
for(int j = W;j >= w[i];j--)
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
cout << dp[W]+sum;
return 0;
}
最后我想说的是,ask函数如果使用传引用可能有问题(我就是有问题,不知道为啥)在这里我是用全局变量来整的,使用int为返回类型更好吧;
int ask(int index,int x){
if(Tree[index].l==Tree[index].r&&Tree[index].l==x){
return Tree[index].tag;
}
if(Tree[index].r<x||Tree[index].l>x)return 0;
Down(index);
int Mid = (Tree[index].l + Tree[index].r)/2;
int a = ask(index<<1,x);
int b = ask(index<<1|1,x);
return a + b;
}