题意翻译
nnn 个数, qqq 次操作
操作0 x y
把 AxA_xAx? 修改为 yyy
操作1 l r
询问区间 [l,r][l, r][l,r] 的最大子段和
感谢 @Edgration 提供的翻译
题目描述
You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.
输入输出格式
输入格式:
The first line of input contains an integer N. The following line contains N integers, representing the sequence A1..AN.
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.
输出格式:
For each query, print an integer as the problem required.
输入输出样例
输入样例#1:
4 1 2 3 4 4 1 1 3 0 3 -3 1 2 4 1 3 3
输出样例#1:
6 4 -3 提交地址 : luogu SP1716spoj; 分析:线段树水题; 用线段树维护四个值 : 这一区间的最大子段和, 这一区间的从最左端开始的最大子段和, 从右端开始的最大子段和,还有这一段的和;怎么维护?
t[o].sum = t[ls(o)].sum + t[rs(o)].sum; t[o].lsum = max(t[ls(o)].lsum, t[ls(o)].sum + t[rs(o)].lsum); t[o].rsum = max(t[rs(o)].rsum, t[rs(o)].sum + t[ls(o)].rsum); t[o].dat = max(t[ls(o)].rsum + t[rs(o)].lsum, max(t[ls(o)].dat, t[rs(o)].dat));
就解释一个:你左端开始的最大子段和一定是你左二子的左端点开始的最大子段和, 还有左二子全选加上右儿子的左端开始的最大子段和;
其他的都大同小异;
一样的按照普通线段树写;
主要讲讲查询操作;
因为我们要找一个连续的序列,而不是每个dat取max;
所以我们要维护一个前缀和qzh;
因为我们维护的是前缀和, 所以每次可以用 qzh+t[o].lsum 和 t[o].dat 取max来更新ans;
然后我们再改变qzh的值 在 qzh + t[o].sum 和 t[o].rsum中取max;
代码奉上:
//zZhBr #include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define int long long inline int read() { int res=0;bool flag=0;char ch=getchar(); while(!isdigit(ch)){if(ch==‘-‘)flag=1;ch=getchar();}; while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-‘0‘);ch=getchar();} return flag?-res:res; } const int N = 50005; int n, a[N], m; int ans, qzh; struct Segment { int ls, rs; int l, r; int sum; int lsum, rsum; int dat; }t[N<<1]; int cnt = 1; int root; #define ls(x) t[x].ls #define rs(x) t[x].rs inline void pushup(int o) { t[o].l = t[ls(o)].l, t[o].r = t[rs(o)].r; t[o].sum = t[ls(o)].sum + t[rs(o)].sum; t[o].lsum = max(t[ls(o)].lsum, t[ls(o)].sum + t[rs(o)].lsum); t[o].rsum = max(t[rs(o)].rsum, t[rs(o)].sum + t[ls(o)].rsum); t[o].dat = max(t[ls(o)].rsum + t[rs(o)].lsum, max(t[ls(o)].dat, t[rs(o)].dat)); } inline void build(int l, int r, int o) { if (l == r) { t[o].sum = a[l]; t[o].lsum = a[l]; t[o].rsum = a[l]; t[o].dat = a[l]; t[o].l = t[o].r = l; return; } int mid = l + r >> 1; t[o].ls = cnt++; t[o].rs = cnt++; build(l, mid, ls(o)); build(mid + 1, r, rs(o)); pushup(o); } inline void change(int o, int x, int v) { if (t[o].l == t[o].r) { t[o].sum = v; t[o].dat = v; t[o].lsum = t[o].rsum = v; return; } int mid = t[o].l + t[o].r >> 1; if (x <= mid) change(ls(o), x, v); else change(rs(o), x, v); pushup(o); } inline void query(int o, int li, int ri) { if (li <= t[o].l and ri >= t[o].r) { ans = max(ans, max(qzh + t[o].lsum, t[o].dat)); qzh = max(qzh + t[o].sum, t[o].rsum); return; } int res = 0; int mid = t[o].r + t[o].l >> 1; if (li <= mid) query(ls(o), li, ri); if (ri > mid) query(rs(o), li, ri); } signed main() { n = read(); for (register int i = 1 ; i <= n ; i ++) a[i] = read(); m = read(); root = cnt++; build(1, n, root); while (m--) { int opt = read(); int x = read(), y = read(); if (opt == 0) { change(root, x, y); } else { ans = -1e9, qzh = -1e9; query(root, x, y); printf("%lld\n", ans); } } return 0; }
原文地址:https://www.cnblogs.com/zZh-Brim/p/9112431.html