做法2:使用懒惰标记,每次修改都对懒惰标记进行操作,每次到达一个节点都 tag[o] 标记下传更新 tree[ls/rs] 的权值,tag[o]标记还原1e9,就可以快速获取每个物品的最小重量。链接:https://ac.nowcoder.com/acm/contest/917/E
来源:牛客网希望
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld题目描述
题目背景
那一瞬间,一道白光闪过,从此大地上再也没有了丝毫的响动
那是一个黑暗的晚上。
新纪元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≤10^5;1≤k≤500;1≤C[i]≤500;1≤L[i]≤R[i]≤n;-10^9≤b[i]≤10^9 新纪596α 12:00:14水宝宝用沾满汗水的双手拉动了操纵杆,将等离子炮对准了勇者号主控台。 “再见。勇士们。”水宝宝向勇者号发送了它能接收的最后一条信息。 水宝宝用微颤的手摁下了Enter。 一声巨响后,世界重归宁静。 英雄们倒在了炮火里,没有痛苦。 整个世界只剩毁灭号引擎的轰鸣。 如果失去了勇者号,我们只能孤注一掷。 人类最后的希望,R8IO核弹。 北半球的天空,从此只有黑夜。
做法1:最多n个物品,对l~r之间的物品重量 用线段树进行区间修改,并查询每个合法物品的最小重量,然后用滚动数组 01背包问题dp,即可得出答案。
#include<bits/stdc++.h> #define ls o*2 #define rs o*2+1 #define mid (l+r)/2 using namespace std; struct node { int v,w; }; int a[100005]; vector<node> aa; int dp[505]={0}; int cnt=1; int n,k,m; int sum=0; vector<int> que; int tree[4*100005]; void up(int o,int l,int r,int ql,int qr,int v) { if(ql<=l&&r<=qr) { tree[o]=min(tree[o],v);//不断对一个节点更新最小值 return ; } if(ql<=mid) up(ls,l,mid,ql,qr,v); if(mid<qr) up(rs,mid+1,r,ql,qr,v); return ; } int qu(int o,int l,int r,int ql,int qr) { if(l==r) return tree[o]; if(ql<=mid) return min(tree[o],qu(ls,l,mid,ql,qr));//不断取当前路径上的最小值 else return min(tree[o],qu(rs,mid+1,r,ql,qr)); } int main() { scanf("%d%d%d",&n,&k,&m); for(int i=1;i<=n;i++) { int v; scanf("%d",&a[i]); sum+=a[i]; } for(int i=1;i<=4*100005;i++) tree[i]=1e9;//每个节点初始化为无穷大 for(int i=0;i<m;i++) { int a,ab,w; scanf("%d%d%d",&a,&ab,&w); up(1,1,n,a,ab,w); } for(int i=1;i<=n;i++) { if(a[i]<0) { node cc; cc.v=-1*a[i]; cc.w=qu(1,1,n,i,i); aa.push_back(cc); } } int ans=0; cnt=aa.size(); for(int i=0;i<cnt;i++) { for(int j=k;j>=0;j--) { if(j>=aa[i].w)dp[j]=max(dp[j],dp[j-aa[i].w]+aa[i].v);//01背包 使用一维数组 / 滚动数组 if(j==k) ans=max(ans,dp[k]); } } printf("%d\n",sum+ans); }
做法2:使用懒惰标记,每次修改都对懒惰标记进行操作,每次到达一个节点都 tag[o] 标记下传更新 tree[ls/rs] 的权值,tag[o]标记还原1e9,就可以快速获取每个物品的最小重量。
#include<bits/stdc++.h> #define ls o*2 #define rs o*2+1 #define mid (l+r)/2 using namespace std; struct node { int v,w; }; int a[100005]; vector<node> aa; int dp[505]={0}; int cnt=1; int n,k,m; int sum=0; vector<int> que; int tree[4*100005],tag[4*100005]; void pushdown(int o) { if(tag[o]!=1e9)//标记有意义则下传 { tag[ls]=min(tag[ls],tag[o]);//标记下传 tag[rs]=min(tag[rs],tag[o]); tree[ls]=min(tree[ls],tag[ls]);//对子节点修改!!!! tree[rs]=min(tree[rs],tag[rs]);//不是对当前节点修改!!! tag[o]=1e9;//初始化标记 } } void up(int o,int l,int r,int ql,int qr,int v) { if(ql<=l&&r<=qr) { tree[o]=min(tree[o],v);//不断对一个节点更新最小值 tag[o]=min(tag[o],v);//标记修改 return ; } pushdown(o);//下传函数位置!!! if(ql<=mid) up(ls,l,mid,ql,qr,v); if(mid<qr) up(rs,mid+1,r,ql,qr,v); return ; } int qu(int o,int l,int r,int ql,int qr) { if(l==r) return tree[o]; pushdown(o);//传函数位置!!! if(ql<=mid) { return qu(ls,l,mid,ql,qr); } else { return qu(rs,mid+1,r,ql,qr); } } int main() { scanf("%d%d%d",&n,&k,&m); for(int i=1;i<=n;i++) { int v; scanf("%d",&a[i]); sum+=a[i]; } for(int i=1;i<=4*100005;i++) tree[i]=1e9,tag[i]=1e9;//每个节点初始化为无穷大 for(int i=0;i<m;i++) { int a,ab,w; scanf("%d%d%d",&a,&ab,&w); up(1,1,n,a,ab,w); } for(int i=1;i<=n;i++) { if(a[i]<0) { node cc; cc.v=-1*a[i]; cc.w=qu(1,1,n,i,i); aa.push_back(cc); } } int ans=0; cnt=aa.size(); for(int i=0;i<cnt;i++) { for(int j=k;j>=0;j--) { if(j>=aa[i].w)dp[j]=max(dp[j],dp[j-aa[i].w]+aa[i].v);//01背包 使用一维数组 / 滚动数组 if(j==k) ans=max(ans,dp[k]); } } printf("%d\n",sum+ans); }
( Lazy 线段树) + 01背包(滚动数组)
猜你喜欢
转载自blog.csdn.net/qq_43868883/article/details/102731743
今日推荐
周排行