3981 动态最大子段和

题目描述 Description

题目还是简单一点好...

有n个数,a[1]到a[n]。

接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和。

子段的意思是连续非空区间。

输入描述 Input Description

第一行一个数n。

第二行n个数a[1]~a[n]。

第三行一个数q。

以下q行每行两个数l和r。

输出描述 Output Description

q行,每行一个数,表示a[l]到a[r]的最大子段和。

样例输入 Sample Input

7
2 3 -233 233 -23 -2 233
4
1 7
5 6
2 5
2 3

样例输出 Sample Output

441
-2
233
3

数据范围及提示 Data Size & Hint

对于50%的数据,q*n<=10000000。

对于100%的数据,1<=n<=200000,1<=q<=200000。

a[1]~a[n]在int范围内,但是答案可能超出int范围。

数据保证1<=l<=r<=n。

空间128M,时间1s。

我不会告诉你数据里有样例

//题意:询问一段区间的最大子序列的值。
//就是GSS1多开点空间然后开longlong 

//做法:维护四个值:包含当前区间左端点的最大子区间LM,包含当前区间右端点的最大子区间RM、当前区间的最大子区间M, 当前区间的区间和S
//tree[root].maxn=max(tree[root<<1].maxn,max(tree[root<<1|1].maxn,tree[root<<1].rmaxn+tree[root<<1|1].lmaxn));
//    tree[root].lmaxn=max(tree[root<<1].lmaxn,tree[root<<1].sum+tree[root<<1|1].lmaxn);
//    tree[root].rmaxn=max(tree[root<<1|1].rmaxn,tree[root<<1|1].sum+tree[root<<1].rmaxn);
//    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=2e5+5;

int n,m,l,r;
long long L,R,M,S;
struct Tree
{
    int l,r,mid;
    long long sum,lmaxn,rmaxn,maxn;
}tree[N<<2];

inline long long read()
{
    char c=getchar();long long num=0,f=1;
    for(;!isdigit(c);c=getchar())
        f=c==‘-‘?-1:f;
    for(;isdigit(c);c=getchar())
        num=num*10+c-‘0‘;
    return num*f;
}

inline void pushup(int root)
{
    tree[root].maxn=max(tree[root<<1].maxn,max(tree[root<<1|1].maxn,tree[root<<1].rmaxn+tree[root<<1|1].lmaxn));
    tree[root].lmaxn=max(tree[root<<1].lmaxn,tree[root<<1].sum+tree[root<<1|1].lmaxn);
    tree[root].rmaxn=max(tree[root<<1|1].rmaxn,tree[root<<1|1].sum+tree[root<<1].rmaxn);
    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
}

void build(int root,int l,int r)
{
    tree[root].l=l,tree[root].r=r,tree[root].mid=l+r>>1;
    if(l==r)
    {
        tree[root].sum=tree[root].maxn=tree[root].rmaxn=tree[root].lmaxn=read();
        return;
    }
    build(root<<1,l,tree[root].mid);
    build(root<<1|1,tree[root].mid+1,r);
    pushup(root);
}

void query(int root,int l,int r,long long &L,long long &R,long long &M,long long &S)
{
    if(l<=tree[root].l&&tree[root].r<=r)
    {
        L=tree[root].lmaxn,
        R=tree[root].rmaxn,
        M=tree[root].maxn,
        S=tree[root].sum;
        return;
    }
    if(tree[root].mid>=r)
    {
        query(root<<1,l,r,L,R,M,S);
    }
    else if(tree[root].mid<l)
    {
        query(root<<1|1,l,r,L,R,M,S);
    }
    else
    {
        long long lL=0,lR=0,lM=0,lS=0,rL=0,rR=0,rM=0,rS=0;
        query(root<<1,l,tree[root].mid,lL,lR,lM,lS);
        query(root<<1|1,tree[root].mid+1,r,rL,rR,rM,rS);
        L=max(lL,lS+rL);
        R=max(rR,rS+lR);
        M=max(lR+rL,max(lM,rM));
        S=lS+rS;
    }
}

int main()
{
    n=read();
    build(1,1,n);
    m=read();
    for(int i=1;i<=m;++i)
    {
        l=read(),r=read();
        query(1,l,r,L,R,M,S);
        printf("%lld\n",M);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lovewhy/p/8747527.html

时间: 2024-10-20 02:12:37

3981 动态最大子段和的相关文章

codevs 3981 动态最大子段和

3981 动态最大子段和 http://codevs.cn/problem/3981/  题目等级 : 钻石 Diamond 题目描述 Description 题目还是简单一点好... 有n个数,a[1]到a[n]. 接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和. 子段的意思是连续非空区间. 输入描述 Input Description 第一行一个数n. 第二行n个数a[1]~a[n]. 第三行一个数q. 以下q行每行两个数l和r. 输出描述 Output Desc

codevs 3981 动态最大子段和(线段树)

题目传送门:codevs 3981 动态最大子段和 题目描述 Description 题目还是简单一点好... 有n个数,a[1]到a[n]. 接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和. 子段的意思是连续非空区间. 输入描述 Input Description 第一行一个数n. 第二行n个数a[1]~a[n]. 第三行一个数q. 以下q行每行两个数l和r. 输出描述 Output Description q行,每行一个数,表示a[l]到a[r]的最大子段和. 样

CODEVS 3981(求最大子段和+线段树)

题目链接:http://codevs.cn/problem/3981/ 参考:https://blog.csdn.net/jokingcoder/article/details/81477253 一个区间的最大子段和有三种情况: 1.等于这个区间左儿子的最大子段和 2.等于这个区间右儿子的最大子段和 3.等于这个区间左儿子的后缀最大子段和+右儿子的前缀最大子段和 tree[k].sumax = max(max(tree[l].sumax,tree[r].sumax),tree[l].rmax +

计划做题列表

估计是做不完.. emmmm  不用估计,是肯定 马上就滚回去学文化课了.... ....列表全都是数据结构... mdzz 我可能是傻了 1.数学  P1214 [USACO1.4]等差数列 Arithmetic Progressions https://www.luogu.org/problemnew/show/P1214 2.P4243 [JSOI2009]等差数列 线段树 https://www.luogu.org/problemnew/show/P4243 主席树 P3313 [SDO

[POI2009]Lyz

Description 初始时滑冰俱乐部有1到n号的溜冰鞋各k双.已知x号脚的人可以穿x到x+d的溜冰鞋. 有m次操作,每次包含两个数ri,xi代表来了xi个ri号脚的人.xi为负,则代表走了这么多人. 对于每次操作,输出溜冰鞋是否足够. Input n m k d ( 1≤n≤200,000 , 1≤m≤500,000 , 1≤k≤10^9 , 0≤d≤n ) ri xi ( 1≤i≤m, 1≤ri≤n-d , |xi|≤10^9 ) Output 对于每个操作,输出一行,TAK表示够 NIE

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\

最大连续子段和的两种线性算法

问题描述:给一个数组a1,a2,...,an.求这个数组的最大连续子段和.(非空子段) 即,定义Sij=ai+...+aj,则题目要求的是 max{Sij}(1<=i<=j<=n) N^3枚举和优化之后的N^2枚举就不说了,还有NlogN的二分算法也不提,想了解的可以看我的另一篇博客:http://www.cnblogs.com/itlqs/p/5097504.html 这里主要详解两种O(n)的算法. 方法一:动态规划 dp[i]表示以第i位为结尾的最大子段和.那么转移方程就是:dp[

(前缀和)51NOD 1081 子段求和

给出一个长度为N的数组,进行Q次查询,查询从第i个元素开始长度为l的子段所有元素之和. 例如,1 3 7 9 -1,查询第2个元素开始长度为3的子段和,1 {3 7 9} -1.3 + 7 + 9 = 19,输出19. Input 第1行:一个数N,N为数组的长度(2 <= N <= 50000). 第2 至 N + 1行:数组的N个元素.(-10^9 <= N[i] <= 10^9) 第N + 2行:1个数Q,Q为查询的数量. 第N + 3 至 N + Q + 2行:每行2个数,

SPOJ GSS3 (动态dp)

题意 题目链接 Sol 这题可以动态dp做. 设\(f[i]\)表示以\(i\)为结尾的最大子段和,\(g[i]\)表示\(1-i\)的最大子段和 那么 \(f[i] = max(f[i - 1] + a[i], a[i])\) \(g[i] = max(g[i - 1], f[i])\) 发现只跟前一项有关,而且\(g[i]从\)f[i]$转移过来的那一项可以直接拆开 那么构造矩阵 \[ \begin{bmatrix} a_{i} & -\infty & \dots a_{i} \\ a