题目描述
“南山之首日鹊山。其首日招摇之山,临于西海之上,多桂,多金玉。有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多棪木,多白猿,多水玉,多黄金。
又东三百八十里,日猨翼之山,其中多怪兽,水多怪鱼,多白玉,多蝮虫,多怪蛇,名怪木,不可以上。……”
《山海经》是以山为纲,以海为线记载古代的河流、植物、动物及矿产等情况,而且每一条记录路线都不会有重复的山出现。某天,你的地理老师想重游《山海经》中的路线,为了简化问题,老师已经把每座山用一个整数表示他对该山的喜恶程度,他想知道第a
座山到第b
座山的中间某段路(i,j)
。能使他感到最满意,即(i,j)
这条路上所有山的喜恶度之和是(c,d)(a≤c≤d≤b)
最大值。
于是老师便向你请教,你能帮助他吗?值得注意的是,在《山海经》中,第i
座山只能到达第i+1
座山。
输入格式
输入第1
行是两个数,n,m,2≤n≤100000,1≤m≤100000
,n
表示一共有n
座山,m
表示老师想查询的数目。
第2
行是n
个整数,代表n
座山的喜恶度,绝对值均小于10000
。
以下m
行每行有a,b
两个数,1≤a≤j≤b≤m
,表示第a
座山到第b
座山。
输出格式
一共有m
行,每行有3
个数i,j,s
,表示从第i
座山到第j
座山总的喜恶度为s
。显然,对于每个查询,有a≤i≤j≤b
,如果有多组解,则输出i
最小的,如果i
也相等,则输出j
最小的解。
样例
样例输入
5 3
5 -6 3 -1 4
1 3
1 5
5 5
样例输出
1 1 5
3 5 6
5 5 4
分析
题意就是让你维护区间最大子段和,如果有多个,输出最靠左的那一个
线段树要维护区间左端点、右端点、最大子段和、最大前缀和、最大后缀和、最大子段和的左右端点、最大前缀和的右端点、最大后缀和的左端点、区间和
合并时,区间最大子段和:左区间最大子段和、右区间最大子段和、左区间最大后缀和+右区间最大前缀和
区间最大前缀和:左区间最大前缀和、左区间和+右区间最大前缀和
区间最大后缀和:右区间最大后缀和、左区间最大后缀和+右区间和
注意更新最大子段和的端点时要注意最左端的优先
代码
#include<cstdio>
const int maxn=1e6+5;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
struct trr{
int l,r,mmax,lmax,rmax,jll,jlr,zb,yb,sum;
trr(){
mmax=rmax=lmax=-0x3f3f3f3f;
jll=zb=0x3f3f3f3f;
jlr=yb=-0x3f3f3f3f;
}
}tr[maxn];
int a[maxn],n,m;
trr push_up(trr aa,trr bb){
trr now;
now.l=aa.l,now.r=bb.r;
now.sum=aa.sum+bb.sum;
if(now.mmax<aa.mmax || (now.mmax==aa.mmax && now.jll>aa.jll)){
now.mmax=aa.mmax;
now.jll=aa.jll;
now.jlr=aa.jlr;
}
if(now.mmax<bb.mmax || (now.mmax==bb.mmax && now.jll>bb.jll)){
now.mmax=bb.mmax;
now.jll=bb.jll;
now.jlr=bb.jlr;
}
if(now.mmax<aa.rmax+bb.lmax || (now.mmax==aa.rmax+bb.lmax && now.jll>aa.yb)){
now.mmax=aa.rmax+bb.lmax;
now.jll=aa.yb;
now.jlr=bb.zb;
}
now.lmax=aa.lmax,now.zb=aa.zb;
if(aa.sum+bb.lmax>now.lmax){
now.lmax=aa.sum+bb.lmax;
now.zb=bb.zb;
}
now.rmax=bb.rmax,now.yb=bb.yb;
if(aa.rmax+bb.sum>=now.rmax){
now.rmax=aa.rmax+bb.sum;
now.yb=aa.yb;
}
return now;
}
void build(int da,int l,int r){
tr[da].l=l,tr[da].r=r;
if(l==r){
tr[da].mmax=tr[da].lmax=tr[da].rmax=tr[da].sum=a[l];
tr[da].jll=tr[da].jlr=tr[da].zb=tr[da].yb=l;
return;
}
int mids=(tr[da].l+tr[da].r)>>1;
build(da<<1,l,mids);
build(da<<1|1,mids+1,r);
tr[da]=push_up(tr[da<<1],tr[da<<1|1]);
}
trr cx(int da,int l,int r){
if(tr[da].l>=l && tr[da].r<=r){
return tr[da];
}
int mids=(tr[da].l+tr[da].r)>>1;
if(l>mids) return cx(da<<1|1,l,r);
else if(r<=mids) return cx(da<<1,l,r);
else return push_up(cx(da<<1,l,r),cx(da<<1|1,l,r));
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
build(1,1,n);
for(int i=1;i<=m;i++){
int l,r;
l=read(),r=read();
trr now=cx(1,l,r);
printf("%d %d %d
",now.jll,now.jlr,now.mmax);
}
return 0;
}