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的询问,输出最大子段和。

输入样例:

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

输出样例:

6
4
-3

解析:用线段树进行维护,记录下每一段的和(sum),最大子段和(maxv),最大前缀(prefix),最大后缀(suffix)。则

sum[o] = sum[o<<1] + sum[o<<1|1] ;

maxv[o] = max( max( maxv[o<<1] , maxv[o<<1|1] ) , suffix[o<<1] + prefix[o<<1|1] ) ;

prefix[o] = max( prefix[o<<1] , sum[o<<1] + prefix[o<<1|1] ) ;

suffix[o] = max( suffix[o<<1|1] , suffix[o<<1] + sum[o<<1|1] ) 。最好统计答案即可。

代码如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define lc o<<1
 4 #define rc o<<1|1
 5 using namespace std;
 6
 7 const int MAXN=50010;
 8 int n,a[MAXN],q,prefix[MAXN*4],suffix[MAXN*4],maxv[MAXN*4],sum[MAXN*4],ans,pre;
 9
10 int read(void) {
11     char c; while (c=getchar(),(c<‘0‘ || c>‘9‘) && c!=‘-‘); int x=0,y=1;
12     if (c==‘-‘) y=-1; else x=c-‘0‘;
13     while (c=getchar(),c>=‘0‘ && c<=‘9‘) x=x*10+c-‘0‘; return x*y;
14 }
15
16 void maintain(int o,int l,int r) { //维护
17     prefix[o]=max(prefix[lc],sum[lc]+prefix[rc]);
18     suffix[o]=max(suffix[rc],sum[rc]+suffix[lc]);
19     maxv[o]=max(maxv[lc],max(maxv[rc],suffix[lc]+prefix[rc]));
20     sum[o]=sum[lc]+sum[rc];
21 }
22
23 void build(int o,int l,int r) { //建树
24     if (l==r) {
25       prefix[o]=a[l];
26       suffix[o]=a[l];
27       maxv[o]=a[l];
28       sum[o]=a[l];
29       return;
30     }
31     int mid=l+r>>1;
32       build(lc,l,mid); build(rc,mid+1,r);
33     maintain(o,l,r);
34 }
35
36 void modify(int o,int l,int r,int p,int x) { //单点修改
37     if (l==r) {
38       prefix[o]=x;
39       suffix[o]=x;
40       maxv[o]=x;
41       sum[o]=x;
42       return;
43     }
44     int mid=l+r>>1;
45       if (p<=mid) modify(lc,l,mid,p,x); else modify(rc,mid+1,r,p,x);
46     maintain(o,l,r);
47 }
48
49 void query(int o,int l,int r,int ql,int qr) { //区间查询
50     if (ql<=l && qr>=r) { //分三种情况考虑,统计答案
51       ans=max(ans,maxv[o]);
52       ans=max(ans,pre+prefix[o]);
53       pre=max(pre+sum[o],suffix[o]);
54       return;
55     }
56     int mid=l+r>>1;
57     if (ql<=mid) query(lc,l,mid,ql,qr);
58     if (qr>mid) query(rc,mid+1,r,ql,qr);
59 }
60
61 int main() {
62     n=read();
63       for (int i=1;i<=n;++i) a[i]=read();
64     build(1,1,n);
65     q=read();
66       while (q--) {
67           int p=read(),x=read(),y=read();
68             if (p) {
69                   ans=pre=-2e9;
70                   query(1,1,n,x,y);
71                   printf("%d\n",ans);
72             }
73           else {
74               modify(1,1,n,x,y);
75           }
76       }
77     return 0;
78 }

原文地址:https://www.cnblogs.com/Gaxc/p/9737816.html

时间: 2024-11-09 10:41:49

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

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

模板——线段树维护最大子段和 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 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】

\[ Preface \] 没有 Preface. \[ Description \] 维护一个长度为 \(n\) 的数列 \(A\) ,需要支持以下操作: 0 x y 将 \(A_x\) 改为 \(y\) . 1 x y 求 \(\max\limits_{x \leq l \leq r \leq y}{\sum_{i=l}^rA[i]}\) . \[ Solution \] 区间最大子段和 是一个非常经典的问题. 对于 整体最大子段和 来说,一般有 \(O(n)\) 的 贪心 和 分治 做法,

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&