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\)为区间子段和最大和。

\(ch[0]\)为左儿子, \(ch[1]\)为右儿子.

考虑维护:

o->sum = ch[0]->sum + ch[1]->sum;
o->ls = max(ch[0]->ls, ch[0]->sum + ch[1]->ls);
o->rs = max(ch[1]->rs, ch[1]->sum + ch[0]->rs);
o->val = max(max(ch[0]->val, ch[1]->val), max(max(o->ls, o->rs), ch[0]->rs + ch[1]->ls);

这样可以考虑到所有的转移情况;

在询问时, 若询问区间跨过左右两个子区间, 则我们利用\(ls, rs, sum\)来更新出当前区间的\(val\);

所以我们返回结构体指针。

题目中为单点修改,考虑如何写up()函数。

发现维护方式与建树时相同。

void up() {
    sum = ch[0]->sum + ch[1]->sum;
    ls = Max(ch[0]->ls, ch[0]->sum + ch[1]->ls);
    rs = Max(ch[1]->rs, ch[1]->sum + ch[0]->rs);
    val = Max(Max(ch[0]->val, ch[1]->val), Max(Max(ls, rs), ch[0]->rs + ch[1]->ls));
}

直接乱搞即可。

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 5e4 + 5;
int read() {
    int x = 0, f = 1; char ch;
    while(! isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(x = ch^48; isdigit(ch = getchar()); x = (x<<3) + (x<<1) + (ch^48));
    return x * f;
}
int n, m;
template <class T> T Max(T a, T b) { return a > b ? a : b; }
struct Segment {
    struct node {
        int l, r, ls, rs, sum, val;
        node *ch[2];
        node(int l, int r, int ls, int rs, int sum, int val) : l(l), r(r), ls(ls), rs(rs), sum(sum), val(val) {
            ch[0] = ch[1] = NULL;
        }
        inline int mid() { return (l + r) >> 1; }
        inline void up() {
            sum = ch[0]->sum + ch[1]->sum;
            ls = Max(ch[0]->ls, ch[0]->sum + ch[1]->ls);
            rs = Max(ch[1]->rs, ch[1]->sum + ch[0]->rs);
            val = Max(Max(ch[0]->val, ch[1]->val), Max(Max(ls, rs), ch[0]->rs + ch[1]->ls));
        }
    } *root;
    void build(node *&o, int l, int r) {
        o = new node(l, r, 0, 0, 0, 0);
        if(l == r) {
            o->ls = o->rs = o->sum = o->val = read();
            return;
        }
        build(o->ch[0], l, o->mid());
        build(o->ch[1], o->mid() + 1, r);
        o->up();
    }
    void change(node *o, int x, int v) {
        if(o->l == x && o->r == x) {
            o->ls = o->rs = o->sum = o->val = v;
            return;
        }
        if(x <= o->mid()) change(o->ch[0], x, v);
        if(x > o->mid()) change(o->ch[1], x, v);
        o->up();
    }
    node *query(node *o, int l, int r) {
        if(l <= o->l && o->r <= r) return o;
        if(r <= o->mid()) return query(o->ch[0], l, r);
        if(l > o->mid()) return query(o->ch[1], l, r);
        node *res = new node(l, r, 0, 0, 0, 0);
        node *t1 = query(o->ch[0], l, r), *t2 = query(o->ch[1], l, r);
        res->sum = t1->sum + t2->sum;
        res->ls = Max(t1->ls, t1->sum + t2->ls);
        res->rs = Max(t2->rs, t2->sum + t1->rs);
        res->val = Max(Max(t1->val, t2->val), Max(Max(res->ls, res->rs), t1->rs + t2->ls));
        return res;
    }
} tr;
int main() {
    n = read();
    tr.build(tr.root, 1, n);
    m = read();
    for(int i = 1, opt, l, r; i <= m; ++ i) {
        opt = read(); l = read(); r = read();
        if(opt & 1) printf("%d\n", tr.query(tr.root, l, r)->val);
        else tr.change(tr.root, l, r);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Paranoid-LS/p/11593000.html

时间: 2024-08-29 05:47:08

SP1716 GSS3 - Can you answer these queries III 线段树的相关文章

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 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&

线段树 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 - 动态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])\] 发现只跟前一项有关.我们希望使用矩阵乘法的思路,但是矩阵乘法通常只能适用于递推问题.因此我们引入广义矩阵乘法. 矩阵乘法问题可分治的原因在于

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

题意:给定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

模板——线段树维护最大子段和 SP1716 GSS3 - Can you answer these queries III

${\color{Pink}{>>Question}}$ 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #define ll long long 7 using namespace std; 8 9 template <typename T> void in

Spoj 1716 Can you answer these queries III 线段树 单点修改 区间求最大子段和

题目链接:点击打开链接 == 原来写1的时候已经把更新函数写好了.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lso

数据结构(线段树):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{