GSS3 - Can you answer these queries III

题意翻译

nnn 个数, qqq 次操作

操作0 x y把 AxA_xAx? 修改为 yyy

操作1 l r询问区间 [l,r][l, r][l,r] 的最大子段和

感谢 @Edgration 提供的翻译

题目描述

You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations:
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

输入输出格式

输入格式:

The first line of input contains an integer N. The following line contains N integers, representing the sequence A1..AN.
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

输出格式:

For each query, print an integer as the problem required.

输入输出样例

输入样例#1:

4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3

输出样例#1:

6
4
-3

提交地址 : luogu SP1716spoj;

分析:线段树水题;

用线段树维护四个值 : 这一区间的最大子段和, 这一区间的从最左端开始的最大子段和, 从右端开始的最大子段和,还有这一段的和;怎么维护?
	t[o].sum = t[ls(o)].sum + t[rs(o)].sum;
	t[o].lsum = max(t[ls(o)].lsum, t[ls(o)].sum + t[rs(o)].lsum);
	t[o].rsum = max(t[rs(o)].rsum, t[rs(o)].sum + t[ls(o)].rsum);
	t[o].dat = max(t[ls(o)].rsum + t[rs(o)].lsum, max(t[ls(o)].dat, t[rs(o)].dat));

就解释一个:你左端开始的最大子段和一定是你左二子的左端点开始的最大子段和, 还有左二子全选加上右儿子的左端开始的最大子段和;

其他的都大同小异;

一样的按照普通线段树写;

主要讲讲查询操作;

因为我们要找一个连续的序列,而不是每个dat取max;

所以我们要维护一个前缀和qzh;

因为我们维护的是前缀和, 所以每次可以用 qzh+t[o].lsum 和 t[o].dat 取max来更新ans;

然后我们再改变qzh的值 在 qzh + t[o].sum 和 t[o].rsum中取max;

代码奉上:

//zZhBr
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long

inline int read()
{
    int res=0;bool flag=0;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)flag=1;ch=getchar();};
    while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-‘0‘);ch=getchar();}
    return flag?-res:res;
}

const int N = 50005;

int n, a[N], m;
int ans, qzh;

struct Segment
{
    int ls, rs;
    int l, r;
    int sum;
    int lsum, rsum;
    int dat;
}t[N<<1];
int cnt = 1;
int root;
#define ls(x) t[x].ls
#define rs(x) t[x].rs

inline void pushup(int o)
{
    t[o].l = t[ls(o)].l, t[o].r = t[rs(o)].r;
    t[o].sum = t[ls(o)].sum + t[rs(o)].sum;
    t[o].lsum = max(t[ls(o)].lsum, t[ls(o)].sum + t[rs(o)].lsum);
    t[o].rsum = max(t[rs(o)].rsum, t[rs(o)].sum + t[ls(o)].rsum);
    t[o].dat = max(t[ls(o)].rsum + t[rs(o)].lsum, max(t[ls(o)].dat, t[rs(o)].dat));
}

inline void build(int l, int r, int o)
{
    if (l == r)
    {
        t[o].sum = a[l];
        t[o].lsum = a[l];
        t[o].rsum = a[l];
        t[o].dat = a[l];
        t[o].l = t[o].r = l;
        return;
    }

    int mid = l + r >> 1;
    t[o].ls = cnt++;
    t[o].rs = cnt++;
    build(l, mid, ls(o));
    build(mid + 1, r, rs(o));
    pushup(o);
}

inline void change(int o, int x, int v)
{
    if (t[o].l == t[o].r)
    {
        t[o].sum = v;
        t[o].dat = v;
        t[o].lsum = t[o].rsum = v;
        return;
    }

    int mid = t[o].l + t[o].r >> 1;

    if (x <= mid) change(ls(o), x, v);
    else change(rs(o), x, v);
    pushup(o);
}

inline void query(int o, int li, int ri)
{
    if (li <= t[o].l and ri >= t[o].r)
    {
        ans = max(ans, max(qzh + t[o].lsum, t[o].dat));
        qzh = max(qzh + t[o].sum, t[o].rsum);
        return;
    }
    int res = 0;
    int mid = t[o].r + t[o].l >> 1;
    if (li <= mid) query(ls(o), li, ri);
    if (ri > mid) query(rs(o), li, ri);
}

signed main()
{
    n = read();
    for (register int i = 1 ; i <= n ; i ++) a[i] = read();
    m = read();
    root = cnt++;
    build(1, n, root);

    while (m--)
    {
        int opt = read();
        int x = read(), y = read();

        if (opt == 0)
        {
            change(root, x, y);
        }
        else
        {
            ans = -1e9, qzh = -1e9;
            query(root, x, y);
            printf("%lld\n", ans);
        }
    }

    return 0;

}

原文地址:https://www.cnblogs.com/zZh-Brim/p/9112431.html

时间: 2024-11-25 17:21:58

GSS3 - Can you answer these queries III的相关文章

数据结构(线段树):SPOJ GSS3 - Can you answer these queries III

GSS3 - Can you answer these queries III You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations: modify the i-th element in the sequence or for given x y print max{

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

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

SP1716 GSS3 - Can you answer these queries III 题意翻译 n 个数,q 次操作 操作0 x y把A_xAx 修改为yy 操作1 l r询问区间[l, r] 的最大子段和 依旧是维护最大子段和,还是再敲一遍比较好. code: #include<iostream> #include<cstdio> #define ls(o) o<<1 #define rs(o) o<<1|1 using namespace std

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\

SP1716 GSS3 - Can you answer these queries III(单点修改,区间最大子段和)

题意翻译 nnn 个数, qqq 次操作 操作0 x y把 AxA_xAx? 修改为 yyy 操作1 l r询问区间 [l,r][l, r][l,r] 的最大子段和 题目描述 You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations: modify the i-th ele

SP1716 GSS3 - Can you answer these queries III - 动态dp,线段树

GSS3 Description 动态维护最大子段和,支持单点修改. Solution 设 \(f[i]\) 表示以 \(i\) 为结尾的最大子段和, \(g[i]\) 表示 \(1 \sim i\) 的最大子段和,那么 \[f[i] = max(f[i - 1] + a[i], a[i])\] \[g[i] = max(g[i - 1], f[i])\] 发现只跟前一项有关.我们希望使用矩阵乘法的思路,但是矩阵乘法通常只能适用于递推问题.因此我们引入广义矩阵乘法. 矩阵乘法问题可分治的原因在于

SPOJ GSS3 Can you answer these queries III ——线段树

[题目分析] GSS1的基础上增加修改操作. 同理线段树即可,多写一个函数就好了. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream&

SPOJ GSS3 Can you answer these queries III

Time Limit: 330MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Description You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations: modify the i-th

SP1716 GSS3 - Can you answer these queries III

题意:给定n个数a[1]~a[n],有q次操作. 操作 0 x y:把第a[x]修改为y: 操作 1 x y:询问x到y的的最大子段和. 输入:第一行:一个正整数n,表示有n个整数: 第二行:n个整数,表示数列: 第三行:一个正整数q,表示有q个询问: 第4~q+3行:每行三个数p,x,y,表示三种操作. 输出:对于每一个种类为1的询问,输出最大子段和. 输入样例: 41 2 3 441 1 30 3 -31 2 41 3 3 输出样例: 64-3 解析:用线段树进行维护,记录下每一段的和(su