TZOJ 4021 Ugly Problem(线段树区间子段最大)
描述
给定一个序列A[0],A[1],…A[N-1],要求找到p0,p1,p2,p3使得A[p0]+A[p0+1]+…+A[p1] + A[p2]+A[p2+1]+…+A[p3]最大(0<=p0<=p1<p2<=p3<N)。你只需要求出这个最大值就可以。
输入
输入的第一行为一个数N(2<=N<=10000),接下来的一行为N个整数(-100<A[i]<100)。
输出
输出一个整数表示最大值。
样例输入
5
-1 -2 -4 -5 4
样例输出
3
题意
如上。
题解
枚举分割点,求左区间最大子段和和到右区间最大字段和。
区间最大值段和是一个经典题,线段树维护。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=10005; 4 struct node{ 5 int sum,lmax,rmax,lrs; 6 }tree[maxn<<2]; 7 void pushup(int x){ 8 tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; 9 tree[x].lmax=max(tree[x<<1].lmax,tree[x<<1|1].lmax+tree[x<<1].sum); 10 tree[x].rmax=max(tree[x<<1|1].rmax,tree[x<<1].rmax+tree[x<<1|1].sum); 11 tree[x].lrs=max(max(tree[x<<1].lrs,tree[x<<1|1].lrs),tree[x<<1].rmax+tree[x<<1|1].lmax); 12 } 13 void build(int l,int r,int p){ 14 if(l==r){ 15 scanf("%d",&tree[p].sum); 16 tree[p].lmax=tree[p].lrs=tree[p].rmax=tree[p].sum; 17 return; 18 } 19 int mid=(l+r)>>1; 20 build(l,mid,p<<1); 21 build(mid+1,r,p<<1|1); 22 pushup(p); 23 } 24 void update(int k,int v,int l,int r,int p){ 25 if(l==r){ 26 tree[p].lmax=tree[p].lrs=tree[p].rmax=tree[p].sum=v; 27 return; 28 } 29 int mid=(l+r)>>1; 30 if(k<=mid)update(k,v,l,mid,p<<1); 31 else update(k,v,mid+1,r,p<<1|1); 32 pushup(p); 33 } 34 node quert(int L,int R,int l,int r,int p){ 35 if(L<=l&&r<=R)return tree[p]; 36 int mid=(l+r)>>1; 37 node vis,f1,f2; 38 vis.sum=0; 39 if(L<=mid)vis=f1=quert(L,R,l,mid,p<<1); 40 if(R>mid)vis=f2=quert(L,R,mid+1,r,p<<1|1); 41 if(L<=mid&&R>mid){ 42 vis.sum=f1.sum+f2.sum; 43 vis.lmax=max(f1.lmax,f1.sum+f2.lmax); 44 vis.rmax=max(f2.rmax,f2.sum+f1.rmax); 45 vis.lrs=max(max(f1.lrs,f2.lrs),f1.rmax+f2.lmax); 46 } 47 return vis; 48 } 49 int main(){ 50 int n,maxx=-1e9; 51 scanf("%d",&n); 52 build(1,n,1); 53 for(int i=1;i<n;i++) 54 maxx=max(quert(1,i,1,n,1).lrs+quert(i+1,n,1,n,1).lrs,maxx); 55 printf("%d\n",maxx); 56 return 0; 57 }