题意:有一个环,有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; }