1. 程式人生 > >FJUT3568 中二病也要敲程式碼(線段樹維護區間連續最值)題解

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; }