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

题目描述

给出了序列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);
    }
}

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

时间: 2024-10-07 23:20:51

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

SP1043 GSS1 - Can you answer these queries I 线段树

问题描述 LG-SP1043 题解 GSS 系列第一题. \(q\) 个询问,求 \([x,y]\) 的最大字段和. 线段树,维护 \([x,y]\) 的 \(lmax,rmax,sum,val\) ,向上合并即可. 但是注意询问过程中也需要维护这些信息. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; template <typename Tp> void read(Tp &x){ x=0;ch

HDU 4027 Can you answer these queries? (线段树区间求和)

Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 12290    Accepted Submission(s): 2912 Problem Description A lot of battleships of evil are arranged in a line before

HDU 4027 Can you answer these queries?(线段树/区间不等更新)

传送门 Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 18290    Accepted Submission(s): 4308 Description A lot of battleships of evil are arranged in a line before the

HDU 4027—— Can you answer these queries?——————【线段树区间开方,区间求和】

Can you answer these queries? Time Limit:2000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4027 Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use

HDU 4027 Can you answer these queries?(线段树区间开方)

Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 16260    Accepted Submission(s): 3809 Problem Description A lot of battleships of evil are arranged in a line befor

SP1716 GSS3 - Can you answer these queries III 线段树

题目传送门:SP1043 GSS1 - Can you answer these queries I 更好的阅读体验 动态维护子段和最大值 前置知识 静态维护子段和最大值:SP1043 GSS1 - Can you answer these queries I 题解传送 题解: 提供结构体指针线段树写法: 设\(l\)为区间左端点, \(r\)为区间右端点: \(ls\)为以\(l\)为左端点的最大子段和, \(rs\)为以\(r\)为右端点的最大子段和; \(sum\)为区间和, \(val\

hdu4027 Can you answer these queries?(线段树平方减少,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4027 Problem Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the bat

SPOJ GSS3 Can you answer these queries III (线段树)

题目大意: 求区间最大子区间的和. 思路分析: 记录左最大,右最大,区间最大. 注意Q_L  和 Q_R  就好. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 55555 using na

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

HDU 4027 Can you answer these queries?(线段树的单点更新+区间查询)

题目链接 题意 : 给你N个数,进行M次操作,0操作是将区间内的每一个数变成自己的平方根(整数),1操作是求区间和. 思路 :单点更新,区间查询,就是要注意在更新的时候要优化,要不然会超时,因为所有的数开几次方之后都会变成1,所以到了1不用没完没了的更新. 1 //HDU 4027 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <iostream> 6 #defi