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 ;
}
posted @ 2020-01-05 16:02  无名菜鸟1  阅读(296)  评论(0编辑  收藏  举报