问题描述:给定一个环形序列,进行在线操作,每次修改一个元素,输出环上的最大连续子段的和。
分析:涉及到线段树的以下操作:维护区间左边开始的连续最大子段和,从右边开始的连续最大子段和,区间的最大子段和
#include
<
iostream
>
using
namespace
std;
#define
MAXN 100005
#define
Min(a,b) (a<b?a:b)
#define
Max(a,b) (a>b?a:b)
int
n,m;
struct
Node{
int
l,r,mx,lmx,rmx,mn,lmn,rmn,sum,mnnum;
bool
allpos;
}nod[
3
*
MAXN];
void
buildtree(
int
u,
int
l,
int
r){
nod[u].l
=
l;
nod[u].r
=
r;
nod[u].lmx
=
INT_MIN;
nod[u].rmx
=
INT_MIN;
nod[u].mx
=
INT_MIN;
nod[u].lmn
=
INT_MAX;
nod[u].rmn
=
INT_MAX;
nod[u].mn
=
INT_MAX;
nod[u].sum
=
0
;
nod[u].mnnum
=
INT_MAX;
nod[u].allpos
=
true
;
if
(r
==
l)
return
;
buildtree(
2
*
u,l,(l
+
r)
/
2
);
buildtree(
2
*
u
+
1
,(l
+
r)
/
2
+
1
,r);
}
void
insert(
int
u,
int
l,
int
r,
int
val){
if
(nod[u].l
==
l
&&
nod[u].r
==
r){
nod[u].mx
=
val;
nod[u].lmx
=
val;
nod[u].rmx
=
val;
nod[u].mn
=
val;
nod[u].lmn
=
val;
nod[u].rmn
=
val;
nod[u].sum
=
val;
nod[u].mnnum
=
val;
if
(val
>=
0
)
nod[u].allpos
=
true
;
else
nod[u].allpos
=
false
;
return
;
}
if
(l
<=
nod[
2
*
u].r)
insert(
2
*
u,l,r,val);
if
(r
>=
nod[
2
*
u
+
1
].l)
insert(
2
*
u
+
1
,l,r,val);
nod[u].allpos
=
nod[
2
*
u].allpos
&&
nod[
2
*
u
+
1
].allpos;
nod[u].sum
=
nod[
2
*
u].sum
+
nod[
2
*
u
+
1
].sum;
nod[u].lmx
=
Max(nod[
2
*
u].lmx,nod[
2
*
u].sum
+
nod[
2
*
u
+
1
].lmx);
nod[u].rmx
=
Max(nod[
2
*
u
+
1
].rmx,nod[
2
*
u
+
1
].sum
+
nod[
2
*
u].rmx);
//
nod[u].mx=Max(nod[2*u].rmx+nod[2*u+1].lmx,nod[2*u].mx,nod[2*u+1].mx);
nod[u].mx
=
nod[
2
*
u].rmx
+
nod[
2
*
u
+
1
].lmx;
nod[u].mx
=
Max(nod[u].mx,nod[
2
*
u].mx);
nod[u].mx
=
Max(nod[u].mx,nod[
2
*
u
+
1
].mx);
nod[u].lmn
=
Min(nod[
2
*
u].lmn,nod[
2
*
u].sum
+
nod[
2
*
u
+
1
].lmn);
nod[u].rmn
=
Min(nod[
2
*
u
+
1
].rmn,nod[
2
*
u
+
1
].sum
+
nod[
2
*
u].rmn);
//
nod[u].mn=Min(nod[2*u].rmn+nod[2*u+1].lmn,nod[2*u].mn,nod[2*u+1].mn);
nod[u].mn
=
nod[
2
*
u].rmn
+
nod[
2
*
u
+
1
].lmn;
nod[u].mn
=
Min(nod[u].mn,nod[
2
*
u].mn);
nod[u].mn
=
Min(nod[u].mn,nod[
2
*
u
+
1
].mn);
nod[u].mnnum
=
Min(nod[
2
*
u].mnnum,nod[
2
*
u
+
1
].mnnum);
//
环内最小的数,当环内元素全部为非负时用到
}
int
main(){
int
i,pos,a,mn;
while
(scanf(
"
%d
"
,
&
n)
!=
EOF){
buildtree(
1
,
1
,n);
mn
=
INT_MAX;
for
(i
=
1
;i
<=
n;i
++
){
scanf(
"
%d
"
,
&
a);
if
(a
<
mn)
mn
=
a;
insert(
1
,i,i,a);
}
scanf(
"
%d
"
,
&
m);
for
(i
=
0
;i
<
m;i
++
){
scanf(
"
%d%d
"
,
&
pos,
&
a);
if
(a
<
mn)
mn
=
a;
insert(
1
,pos,pos,a);
if
(nod[
1
].allpos)
//
当环内元素全为非负时
printf(
"
%d\n
"
,nod[
1
].sum
-
nod[
1
].mnnum);
//
解为环和去掉最小的一个元素
else
printf(
"
%d\n
"
,Max(nod[
1
].sum
-
nod[
1
].mn,nod[
1
].mx));
//
解为环和减去最小子列和最大子列两者中的较大值
}
}
return
0
;
}