01背包(线段树维护最小花费)
https://ac.nowcoder.com/acm/contest/3800/B
题意:给你n个数,k能量,m种区间,区间内可以删除一个数但需要消耗能量,如何使总和最大。
解法:线段树维护每个数的最小花费的能量,如何对可删除的数进行删与不删两种选择,就是01背包问题。
//#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <algorithm> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdio.h> #include <queue> #include <stack>; #include <map> #include <set> #include <ctype.h> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SF(n) scanf("%d" , &n) #define rep(i , n) for(int i = 0 ; i < n ; i ++) #define INF 0x3f3f3f3f #define mod 1000000007 #define PI acos(-1) using namespace std; typedef long long ll ; const int N = 100009; int val[N] , v[N] , w[N] , dp[509]; struct node{ int l , r , val , tag; }tree[N << 2]; void build(int l , int r , int root) { tree[root].l = l , tree[root].r = r , tree[root].val = INF ; if(l == r) return ; int mid = (l + r) >> 1 ; build(l , mid , root*2); build(mid+1 , r , root*2+1); } void down(int root) { tree[root*2].val = min(tree[root*2].val , tree[root].val); tree[root*2+1].val = min(tree[root*2+1].val , tree[root].val); } void update(int l , int r , int val , int root)//区间更新 { if(tree[root].l >= l && tree[root].r <= r) { tree[root].val = min(val , tree[root].val); return ; } down(root); int mid = (tree[root].l + tree[root].r) >> 1; if(l <= mid) update(l , r , val , root*2); if(r > mid) update(l , r , val , root*2+1); } int ask(int x , int root)//单点查询 { if(tree[root].l == tree[root].r) { return tree[root].val ; } down(root); int mid = (tree[root].l + tree[root].r) >> 1 ; if(x <= mid) { return ask(x , root*2); } else { return ask(x , root*2+1); } } int main() { /*#ifdef ONLINE_JUDGE #else freopen("D:/c++/in.txt", "r", stdin); freopen("D:/c++/out.txt", "w", stdout); #endif*/ int n , k , m , sum = 0; scanf("%d%d%d" , &n , &k , &m); for(int i = 1 ; i <= n ; i++) { scanf("%d" , &val[i]); sum += val[i]; } build(1 , n , 1); for(int i = 0 ; i < m ; i++) { int l , r , x ; scanf("%d%d%d" , &l ,&r , &x); update(l , r , x , 1); } int cnt = 0 ; for(int i = 1 ; i <= n ; i++) { if(val[i] < 0) { v[cnt] = -val[i]; w[cnt] = ask(i , 1); cnt++; } } for(int i = 0 ; i < cnt ; i++) { for(int j = k ; j >= w[i] ; j--) { dp[j] = max(dp[j] , dp[j-w[i]]+v[i]); } } cout << sum + dp[k] << endl ; return 0 ; }