FJUT3568 中二病也要敲代码(线段树维护区间连续最值)题解

题意:有一个环,有1~N编号,m次操作,将a位置的值改为b,问你这个环当前最小连续和多少(不能全取也不能不取)

思路:用线段树维护一个区间最值连续和。我们设出两个变量Lmin,Rmin,Mmin表示区间左边最小连续和,右边最小连续和,区间最小连续和,显然这可以通过这个方式更新维护。

现在我们已经可以维护一个区间最值连续和了,那么怎么求“环”的最小连续和呢?显然如果最小区间横跨1和n是不能表示出来的(比如最小区间是2,1,n,n-1之和),那么我们可以转化为求sum-Mmax即区间和减去区间最大值,那么显然最终答案是min( sum[1] - Mmax[1], Mmin[1] ),但由题意“不能全取也不能不取”,那么特判。

好久没做线段树维护连续区间的题了...

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x)  x&-x;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 1e5+5;
const ll mod = 1e8+7;
ll Lmax[maxn << 2], Rmax[maxn << 2], Mmax[maxn << 2], sum[maxn << 2];
ll Lmin[maxn << 2], Rmin[maxn << 2], Mmin[maxn << 2];
ll a[maxn];
void push_up(int rt){
    Lmax[rt] = max(Lmax[rt << 1], sum[rt << 1] + Lmax[rt << 1 | 1]);
    Rmax[rt] = max(Rmax[rt << 1 | 1], sum[rt << 1 | 1] + Rmax[rt << 1]);
    Mmax[rt] = max(max(Mmax[rt << 1], Mmax[rt << 1 | 1]), Rmax[rt << 1] + Lmax[rt << 1 | 1]);
    Lmin[rt] = min(Lmin[rt << 1], sum[rt << 1] + Lmin[rt << 1 | 1]);
    Rmin[rt] = min(Rmin[rt << 1 | 1], sum[rt << 1 | 1] + Rmin[rt << 1]);
    Mmin[rt] = min(min(Mmin[rt << 1], Mmin[rt << 1 | 1]), Rmin[rt << 1] + Lmin[rt << 1 | 1]);
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int l, int r, int rt){
    if(l == r){
        Mmax[rt] = Rmax[rt] = Lmax[rt] = Mmin[rt] = Rmin[rt] = Lmin[rt] = sum[rt] = a[l];
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    push_up(rt);
}
void update(int pos, int l, int r, int v, int rt){
    if(l == r){
        Mmax[rt] = Rmax[rt] = Lmax[rt] = Mmin[rt] = Rmin[rt] = Lmin[rt] = sum[rt] = v;
        return;
    }
    int m = (l + r) >> 1;
    if(pos <= m)
        update(pos, l, m, v, rt << 1);
    else
        update(pos, m + 1, r, v, rt << 1 | 1);
    push_up(rt);
}
int main(){
    int n, m, A;
    ll B;
    while(~scanf("%d", &n)){
        for(int i = 1; i <= n; i++){
            scanf("%lld", &a[i]);
        }
        build(1, n, 1);
        scanf("%d", &m);
        while(m--){
            ll MAX, MIN, ans;
            scanf("%d%lld", &A, &B);
            update(A, 1, n, B, 1);
            if(Mmax[1] == sum[1]){
                ans = Mmin[1];
            }
            else if(Mmin[1] == sum[1]){
                ans = Mmin[1] - Mmax[1];
            }
            else{
                ans = min(sum[1] - Mmax[1], Mmin[1]);
            }
            printf("%lld\n", ans);
        }
    }
    return 0;
}

 

posted @ 2018-10-31 21:46  KirinSB  阅读(164)  评论(0编辑  收藏  举报