1. 程式人生 > >SP1043 GSS1 - Can you answer these queries I(線段樹,區間最大子段和(靜態))

SP1043 GSS1 - Can you answer these queries I(線段樹,區間最大子段和(靜態))

有一種 nbsp 不用 端點 合並 表示 格式 space iostream

題目描述

給出了序列A[1],A[2],…,A[N]。 (a[i]≤15007,1≤N≤50000)。查詢定義如下: 查詢(x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y}。 給定M個查詢,程序必須輸出這些查詢的結果。

輸入輸出格式

輸入格式:

  • 輸入文件的第一行包含整數N。
  • 在第二行,N個數字跟隨。
  • 第三行包含整數M。
  • M行跟在後面,其中第1行包含兩個數字xi和yi。

輸出格式:

您的程序應該輸出M查詢的結果,每一行一個查詢。

思路:

我們做這道題首先應該想的,是兩個區間如何合並

很顯然,合並後最大子段和,要麽是原來左兒子的,要麽是原來右兒子的

還有一種可能是左右兩個兒子合並後在中間新生成的

所以,每個節點維護四個元素

分別表示他所管轄的區間和,他所管轄的區間中的最大連續子段和

從左起最大連續子段和(意思是子段的左端點一定是區間的左端點)

從右起最大連續子段和(意思同上)

此時我們可以這樣轉移:

sum(和)就不用說了

這一層的從左起最大連續子段和=max(左兒子的從左起最大連續子段和,左兒子的和+右兒子的從左起最大連續子段和)

這一層的從左起最大連續子段和方法同上

這一層的最大連續子段和=max(左兒子的最大連續子段和,右兒子的最大連續子段和,(左兒子從右起的最大連續字段和+右兒子從左起的最大連續子段和(也就是合並後生成的中間最大子段)))

OK,任務完成

查詢同理

代碼:

//這裏我將建樹當成更改節點值
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rii register int i
#define rij register int j
#define inf 1073741824
#define rs 65536
using namespace std;
struct nod{
    int lm,rm,maxn,sum;
}x[
6000005]; int n,q,cz,x1,y1; void add(int wz,int l,int r,int val,int bh) { if(l==r&&l==wz) { x[bh].maxn=val; x[bh].lm=val; x[bh].rm=val; x[bh].sum=val; return; } int ltt=(l+r)/2; if(wz<=ltt) { add(wz,l,ltt,val,bh*2); } else { add(wz,ltt+1,r,val,bh*2+1); } x[bh].sum=x[bh*2].sum+x[bh*2+1].sum; x[bh].lm=max(x[bh*2].lm,x[bh*2].sum+x[bh*2+1].lm); x[bh].rm=max(x[bh*2+1].rm,x[bh*2+1].sum+x[bh*2].rm); x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rm+x[bh*2+1].lm)); } nod query(int l,int r,int nl,int nr,int bh) { nod an,bn; if(l<nl) { l=nl; } if(r>nr) { r=nr; } if(nl==l&&nr==r) { an=x[bh]; return an; } int ltt=(nl+nr)/2; if(l<=ltt&&r<=ltt) { return an=query(l,r,nl,ltt,bh*2); } if(r>ltt&&l>ltt) { return bn=query(l,r,ltt+1,nr,bh*2+1); } else { an=query(l,r,nl,ltt,bh*2); bn=query(l,r,ltt+1,nr,bh*2+1); an.maxn=max(an.maxn,max(bn.maxn,an.rm+bn.lm)); an.lm=max(an.lm,an.sum+bn.lm); an.rm=max(bn.rm,bn.sum+an.rm); an.sum=an.sum+bn.sum; return an; } } int main() { // freopen("brs.in","r",stdin); // freopen("brs.out","w",stdout); for(rii=1;i<=150005;i++) { x[i].lm=-inf; x[i].rm=-inf; x[i].maxn=-inf; } scanf("%d",&n); for(rii=1;i<=n;i++) { int ltt; scanf("%d",&ltt); add(i,1,rs,ltt,1); } scanf("%d",&q); for(rii=1;i<=q;i++) { scanf("%d%d",&x1,&y1); nod ans=query(x1,y1,1,rs,1); printf("%d\n",ans.maxn); } }

SP1043 GSS1 - Can you answer these queries I(線段樹,區間最大子段和(靜態))