題目描述
“南山之首日鵲山。其首日招搖之山,臨於西海之上,多桂,多金玉。有草焉,其狀如韭而青華,其名日祝餘,食之不飢……又東三百里,日堂庭之山,多棪木,多白猿,多水玉,多黃金。
又東三百八十里,日猨翼之山,其中多怪獸,水多怪魚,多白玉,多蝮蟲,多怪蛇,名怪木,不可以上。……”
《山海經》是以山為綱,以海為線記載古代的河流、植物、動物及礦產等情況,而且每一條記錄路線都不會有重複的山出現。某天,你的地理老師想重遊《山海經》中的路線,為了簡化問題,老師已經把每座山用一個整數表示他對該山的喜惡程度,他想知道第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\n",now.jll,now.jlr,now.mmax);
}
return 0;
}