码迷,mamicode.com
首页 > 其他好文 > 详细

SP1043 GSS1 - Can you answer these queries I(线段树,区间最大子段和(静态))

时间:2018-07-20 20:32:19      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:应该   代码   space   ret   一个   sp1   输入输出   string   inf   

题目描述

给出了序列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(线段树,区间最大子段和(静态))

标签:应该   代码   space   ret   一个   sp1   输入输出   string   inf   

原文地址:https://www.cnblogs.com/ztz11/p/9343366.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!