【题目大意】
维护一个序列,使之支持一下两种操作:
1、单点修改
2、查询一个区间子区间最大值(在某个区间中任意寻找一段连续子区间,使得该子区间的和最大)(以下将该值称为‘答案’)
【解题思路】
线段树做法:
考虑维护四种和:sum,suml,sumr,subsum,分别是区间和,左端点开始连续最大和(以下将该值称为‘左始和’),右端点结束连续最大和(以下将该值称为‘右结和’),答案
则区间和=左儿子和+右儿子和
左始和=max(左儿子左始和,左儿子区间和+右儿子左始和)
右结和=max(右儿子右结和,右儿子区间和+左儿子右结和)
答案=max(左始和,右结和,左儿子答案,右儿子答案,左儿子右结和+右儿子左始和)
图解:
所有信息维护好之后,由底层至上层最后统计一次答案(可以用一个队列实现)
【代码】(抱歉之前用栈写挂了改成队列没改名字,所以stk变量名可能有点误导)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cctype>
#include<iomanip>
#include<stack>
#include<queue>
#define LL long long
//#define LOCAL
using namespace std;
const int N=100111;
int n,m;
struct Seg_Tree{
struct treenode{
int l,r;
int sum,suml,sumr,subsum;
int lazy;
void Update(int v){
sum=suml=sumr=subsum=v;
}
}tree[N<<2];
queue <int> stk;
void Maintain(int o){
int i=o;
tree[o].sum=tree[o<<1].sum+tree[o<<1|1].sum;
tree[o].suml=max(tree[o<<1].suml,tree[o<<1].sum+tree[o<<1|1].suml);
tree[o].sumr=max(tree[o<<1|1].sumr,tree[o<<1|1].sum+tree[o<<1].sumr);
tree[o].subsum=max(tree[o].suml,max(tree[o].sumr,max(tree[o<<1].subsum,
max(tree[o<<1|1].subsum,tree[o<<1].sumr+tree[o<<1|1].suml))));
}
void Build(int o,int l,int r){
tree[o].l=l;
tree[o].r=r;
tree[o].subsum=0;
tree[o].sum=0;
tree[o].suml=0;
tree[o].sumr=0;
if (l==r) return;
else{
int mid=(l+r)>>1;
Build(o<<1,l,mid);
Build(o<<1|1,mid+1,r);
}
}
void Modify(int o,int pos,int v){
int l=tree[o].l;
int r=tree[o].r;
if (l==pos&&r==pos) tree[o].Update(v);
else{
int mid=(l+r)>>1;
if (pos<=mid) Modify(o<<1,pos,v);
else Modify(o<<1|1,pos,v);
Maintain(o);
}
}
void Anti(int o,int ql,int qr){
int l=tree[o].l;
int r=tree[o].r;
if (ql<=l&&qr>=r) stk.push(o);
else{
int mid=(l+r)>>1;
if (ql<=mid) Anti(o<<1,ql,qr);
if (qr>mid) Anti(o<<1|1,ql,qr);
}
}
int Query(){
int ans,ansl,ansr,subans;
ans=tree[stk.front()].sum;
ansl=tree[stk.front()].suml;
ansr=tree[stk.front()].sumr;
subans=tree[stk.front()].subsum;
stk.pop();
while (!stk.empty()){
int head=stk.front();
stk.pop();
int tmp=ansr;
ansl=max(ansl,ans+tree[head].suml);
ansr=max(tree[head].sumr,tree[head].sum+ansr);
subans=max(subans,max(tree[head].subsum,max(ansl,max(ansr,tmp+tree[head].suml))));
ans+=tree[head].sum;
}
return subans;
}
}SgTree;
int main(){
#ifdef LOCAL
freopen("UESTC844.in","r",stdin);
#endif
while (scanf("%d%d",&n,&m)!=EOF){
SgTree.Build(1,1,n);
for (int i=1;i<=n;++i){
int x;
scanf("%d",&x);
SgTree.Modify(1,i,x);
}
while (m--){
while (!SgTree.stk.empty()) SgTree.stk.pop();
int sign;
scanf("%d",&sign);
if (sign){
int x,y;
scanf("%d%d",&x,&y);
SgTree.Modify(1,x,y);
}
else{
int x,y;
scanf("%d%d",&x,&y);
while (!SgTree.stk.empty()) SgTree.stk.pop();
SgTree.Anti(1,x,y);
printf("%d\n",SgTree.Query());
}
}
}
}
【总结】
此题的维护值略多,需要仔细处理
听说也可以用动归做,回去再研究一下~