【贪心】 51nod 1115 最大M字段和 V3

通道

思路:连续上升,连续下降的值放到set里面,然后对于大于m的集合双向链表进行合并,合并肯定是找绝对值最小的合并。

代码:

#include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;

typedef long long ll;

const int N = 2000005;

ll s[N];
set<pair<ll, int> > a;
int n, m, now;
int pr[N], ne[N];

void Erase(int x) {
    int l = pr[x], r = ne[x];
    ne[l] = r, pr[r] = l;
}
int main() {
    scanf("%d%d", &n, &m);
    ll tem = 0, ans = 0;
    int cnt = 0;
    for(int i = 1, x; i <= n; ++i) {
        scanf("%d", &x);
        if((tem < 0 && x > 0) || (tem > 0 && x < 0)) {
            now += tem > 0;
            s[++cnt] = tem;
            a.insert(make_pair(abs(tem), cnt));
            tem = 0;
        }
        tem += x;
        ans += x > 0 ? x : 0;
    }
    if( ( tem >= 0 && s[1] > 0 ) || ( tem <= 0 && s[1] < 0 ) ) {
       a.erase(make_pair(abs(s[1]),1));
        s[1] += tem;
       a.insert(make_pair(abs(s[1]),1));
    } else {
        now += tem > 0;
        s[++cnt] = tem;
        a.insert( make_pair(abs( tem ), cnt ) );
    }
    for( int i = 1; i <= cnt; ++i ) {
        pr[i] = i - 1, ne[i] = i + 1;
    }
    pr[1] = cnt, ne[cnt] = 1;
    for( ; now > m; --now ) {
        int x = ( *a.begin() ).second;
        a.erase( make_pair(abs(s[x] ), x ) );
        a.erase( make_pair(abs(s[pr[x]] ), pr[x] ) ), a.erase(make_pair(abs( s[ne[x]] ), ne[x] ) );
        ans -= abs( s[x] );
        s[x] = s[x] + s[pr[x]] + s[ne[x]];
        Erase( pr[x] );
        Erase( ne[x] );
        a.insert( make_pair(abs( s[x]), x ) );
    }
    printf( "%I64d\n", ans );
    return 0;
}
View Code

 

posted @ 2015-10-01 15:35  mithrilhan  阅读(290)  评论(0编辑  收藏  举报