CodeForces 332B Maximum Absurdity(线段树单点更新)

题意:

给你一个序列,找两个长度为 k 且没有重合区间的数使得其和最大

解析:

线段树,就是把起点为 i 长度为 k 的和预处理出来,再枚举a,与a线段不重合的,后面的部分用线段树来找最大位置,总复杂度 O(nlog(n))

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;

ll sumv[N<<2], x[N];

void build(int o, int L, int R) {
    if(L == R) {
        sumv[o] = x[L];
        return ;
    }
    int M = (L+R)/2;
    build(lson);
    build(rson);
    sumv[o] = sumv[ls] + sumv[rs];
}

ll query(int o, int L, int R, int ql, int qr) {
    if(ql <= L && R <= qr)
        return sumv[o];
    int M = (L + R)/2;
    ll ret = 0;
    if(ql <= M) ret += query(lson, ql, qr);
    if(qr > M) ret += query(rson, ql, qr);
    return ret;
}

struct Segment {
    int L, R;
    ll sum;
} s[N];

ll maxv[N<<2];
int posv[N<<2];
void pushUp(int o) {
    if(maxv[ls] >= maxv[rs]) {
        maxv[o] = maxv[ls];
        posv[o] = posv[ls];
    }else {
        maxv[o] = maxv[rs];
        posv[o] = posv[rs];
    }
}

void build2(int o, int L, int R) {
    if(L == R) {
        maxv[o] = s[L].sum;
        posv[o] = s[L].L;
        return ;
    }
    int M = (L + R)/2;
    build2(lson);
    build2(rson);
    pushUp(o);
}

ll _maxv;
int site;
void find(int o, int L, int R, int ql, int qr) {
    if(ql <= L && R <= qr) {
        if(_maxv < maxv[o]) {
            _maxv = maxv[o];
            site = posv[o];
        }
        return ;
    }
    int M = (L+R)/2;
    if(ql <= M) find(lson, ql, qr);
    if(qr > M) find(rson, ql, qr);
}

int n, k;
int main() {
    while(scanf("%d%d", &n, &k) != EOF) {
        for(int i = 1; i <= n; i++)
            scanf("%lld", &x[i]);

        build(1, 1, n);

        for(int i = 1; i <= n - k + 1; i++) {
            s[i].L = i, s[i].R = i+k-1;
            s[i].sum = query(1, 1, n, s[i].L, s[i].R);
        }

        int last = n-k+1;
        build2(1, 1, last);

        int a, b; 
        ll maxSum = -INF;

        for(int i = 1; i < last; i++) {
            _maxv = -INF;
            find(1, 1, last, s[i].R+1, last);
            if(maxSum < s[i].sum + _maxv) {
                maxSum = s[i].sum + _maxv;  
                a = i, b = site;
            }
        }
        printf("%d %d\n", a, b);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值