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])
\]

发现只跟前一项有关。我们希望使用矩阵乘法的思路,但是矩阵乘法通常只能适用于递推问题。因此我们引入广义矩阵乘法。

矩阵乘法问题可分治的原因在于矩阵乘法满足结合律,而满足结合律的根本原因是乘法对加法满足分配率,即

\[a\cdot (b+c) = a\cdot c + b\cdot c
\]

那么在这里,很容易发现,加法运算对\(Min/Max\)运算也是满足分配率的,即

\[a + min(b,c) = min(a+c,b+c)
\]

\[a + max(b,c) = max(a+c,b+c)
\]

所谓广义矩阵乘法,就是将矩阵乘法中的加法运算换成\(Min/Max\)运算,乘法运算换成加法运算,那么这样的矩阵乘法仍然满足结合律。

考虑到 \(g[i]\) 从 \(f[i]\) 转移过来的那一项可以直接拆开,很容易得到转移方程

\[\begin{bmatrix}
f_{i} \\ g_{i} \\ 0
\end{bmatrix}
=
\begin{bmatrix}
a_{i} & -\infty & a_{i} \\
a_{i} & 0 & a_{i}\\
-\infty & -\infty & 0 \\
\end{bmatrix}
\cdot
\begin{bmatrix}
f_{i-1} \\ g_{i-1} \\ {0}
\end{bmatrix}
\]

可以将其记为

\[F_i = A_i \cdot F_{i-1}
\]

于是我们用线段树暴力维护所有\(A_i\)的乘积即可。复杂度\(O(27n \log{n})\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
struct Matrix {
int n,m,a[5][5];
Matrix() {
n=m=0;
for(int i=0;i<4;i++) for(int j=0;j<4;j++) a[i][j]=0;
}
Matrix operator * (const Matrix &y) {
Matrix r;
if(m!=y.n) return r;
r.n = n; r.m = y.m;
for(int i=1;i<=n;i++) {
for(int j=1;j<=y.m;j++) {
for(int k=1;k<=m;k++) {
if(k==1) r.a[i][j]=a[i][k]+y.a[k][j];
else r.a[i][j]=max(r.a[i][j],a[i][k]+y.a[k][j]);
}
}
}
return r;
}
};
Matrix make(int x) {
Matrix r;
r.m=r.n=3;
r.a[1][1]=r.a[1][3]=r.a[2][1]=r.a[2][3]=x;
r.a[2][2]=r.a[3][3]=0;
r.a[1][2]=r.a[3][1]=r.a[3][2]=-1e+9;
return r;
} const int N = 1000005; Matrix val[N],zero;
int n,q,src[N],t1,t2,t3; void pushup(int p) {
val[p] = val[p*2]*val[p*2+1];
}
void build(int p,int l,int r) {
if(l==r) {
val[p]=make(src[l]);
}
else {
build(p*2,l,(l+r)/2);
build(p*2+1,(l+r)/2+1,r);
pushup(p);
}
}
void modify(int p,int l,int r,int pos,int key) {
if(l==r) {
val[p]=make(key);
}
else {
if(pos<=(l+r)/2) modify(p*2,l,(l+r)/2,pos,key);
else modify(p*2+1,(l+r)/2+1,r,pos,key);
pushup(p);
}
}
Matrix query(int p,int l,int r,int ql,int qr) {
Matrix R=make(-1e+9);
if(l>qr||r<ql) return R;
if(l>=ql&&r<=qr) return val[p];
return query(p*2,l,(l+r)/2,ql,qr)*query(p*2+1,(l+r)/2+1,r,ql,qr);
} signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>src[i];
cin>>q;
zero.n=3; zero.m=1;
zero.a[1][1]=zero.a[2][1]=-1e+9;
build(1,1,n);
for(int i=1;i<=q;i++) {
cin>>t1>>t2>>t3;
if(t1==0) {
modify(1,1,n,t2,t3);
}
else {
Matrix r=query(1,1,n,t2,t3)*zero;
cout<<r.a[2][1]<<endl;
}
}
}

当然似乎这个问题用线段树暴力又短又快

#include <bits/stdc++.h>
using namespace std; int src[1000005],a[1000005],al[1000005],ar[1000005],s[1000005],n,m,t1,t2,t3,t4; struct Result {
int a,al,ar,s;
}; void build(int p,int l,int r) {
if(l==r) a[p]=al[p]=ar[p]=s[p]=src[l];
else {
build(p<<1,l,(l+r)/2),
build(p<<1|1,(l+r)/2+1,r);
a[p]=max(max(a[p<<1],a[p<<1|1]),max(max(ar[p<<1],al[p<<1|1]),ar[p<<1]+al[p<<1|1]));
al[p]=max(al[p<<1],s[p<<1]+max(0,al[p<<1|1]));
ar[p]=max(ar[p<<1|1],max(0,ar[p<<1])+s[p<<1|1]);
s[p]=s[p*2]+s[p*2+1];
}
} void modify(int p,int l,int r,int pos,int key) {
if(l==r) a[p]=al[p]=ar[p]=s[p]=key;
else {
if(pos<=(l+r)/2) modify(p<<1,l,(l+r)/2,pos,key);
else modify(p<<1|1,(l+r)/2+1,r,pos,key);
a[p]=max(max(a[p<<1],a[p<<1|1]),max(max(ar[p<<1],al[p<<1|1]),ar[p<<1]+al[p<<1|1]));
al[p]=max(al[p<<1],s[p<<1]+max(0,al[p<<1|1]));
ar[p]=max(ar[p<<1|1],max(0,ar[p<<1])+s[p<<1|1]);
s[p]=s[p*2]+s[p*2+1];
}
} Result query(int p,int l,int r,int ql,int qr) {
Result res;
res.a=-1e+8;
res.al=-1e+8;
res.ar=-1e+8;
res.s=-1e+8;
if(l>qr||r<ql) return res;
if(l>=ql&&r<=qr) {
res.a=a[p];
res.al=al[p];
res.ar=ar[p];
res.s=s[p];
return res;
}
else {
Result cl,cr;
cl=query(p<<1,l,(l+r)/2,ql,qr);
cr=query(p<<1|1,(l+r)/2+1,r,ql,qr);
res.a=max(max(cl.a,cr.a),max(max(cl.ar,cr.al),cl.ar+cr.al));
res.al=max(cl.al,cl.s+max(0,cr.al));
res.ar=max(cr.ar,max(0,cl.ar)+cr.s);
res.s=cl.s+cr.s;
return res;
}
} int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>src[i];
build(1,1,n);
cin>>m;
for(int i=1;i<=m;i++) {
cin>>t3>>t1>>t2;
if(t3) {
Result res=query(1,1,n,t1,t2);
cout<<res.a<<endl;
}
else {
modify(1,1,n,t1,t2);
}
}
}

SP1716 GSS3 - Can you answer these queries III - 动态dp,线段树的更多相关文章

  1. 线段树 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] ...

  2. 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 give ...

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

    问题描述 [LG-SP1716](https://www.luogu.org/problem/SP1716] 题解 GSS 系列的第三题,在第一题的基础上带单点修改. 第一题题解传送门 在第一题的基础 ...

  4. SP1716 GSS3 - Can you answer these queries III

    题面 题解 相信大家写过的传统做法像这样:(这段代码蒯自Karry5307的题解) struct SegmentTree{ ll l,r,prefix,suffix,sum,maxn; }; //.. ...

  5. SPOJ GSS3 Can you answer these queries III[线段树]

    SPOJ - GSS3 Can you answer these queries III Description You are given a sequence A of N (N <= 50 ...

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

  7. 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 提供的 ...

  8. Can you answer these queries? HDU - 4027 (线段树,区间开平方,区间求和)

    A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use ...

  9. 【SP1716】GSS3 - Can you answer these queries III(动态DP)

    题目链接 之前用线段树写了一遍,现在用\(ddp\)再写一遍. #include <cstdio> #define lc (now << 1) #define rc (now ...

随机推荐

  1. css基础-盒子模型+背景和列表

    border-style的值: none 无 dotted 点状 dashed 虚线 solid 实线 double 双实线 margin: 垂直方向两个相邻元素都设置了外边距,那么外边距会发生合并 ...

  2. Auto-Encoder(自编码器)原理

    1.无监督学习 无监督学习和监督学习是机器学习的两个方向,监督学习主要适用于已经标注好的数据集(如mnist分类问题),无监督学习则是希望计算机完成复杂的标注任务,简单的解释就是——教机器自己学习,它 ...

  3. final关键字在JVM中的理解

    我们先来看两段代码与运行结果,根据结果去分析解释一下 不加final关键字: package com.waibizi; public class demo02 { public static void ...

  4. 学习postgresql spi(一)

    #include "postgres.h" #include #include "fmgr.h" #include "access/xlog.h&qu ...

  5. 本地连接mysql的url写法

    一.jdbc:mysql:///中三条斜杠(///) 第三个/代表什么? jdbc:mysql:///testdatabase等同于 jdbc:mysql://localhost:3306/testd ...

  6. linux(服务器)如何确认网卡(网口)对应的配置文件

    服务器装完系统就要配置网络,然而服务器经常是多网卡多网口,我们在某个网口插上网线后,到/etc/sysconfig/network-scripts/下配置ip时无法确定网口对应的配置文件.(比如是et ...

  7. 【学习笔记】BP神经网络

    转自 huaweizte123的CSDN博客  链接 https://blog.csdn.net/huaweizte123/article/details/78803045 第一步.向前传播得到预测数 ...

  8. Android 开发调试最优选项

    1 开发环境 VS2019 16.4.5 2 开发调试选项 Android 选项

  9. 0级搭建类009-Fedora 30 安装(F30) 公开

    项目文档引子系列是根据项目原型,制作的测试实验文档,目的是为了提升项目过程中的实际动手能力,打造精品文档AskScuti. 项目文档引子系列目前不对外发布,仅作为博客记录.如学员在实际工作过程中需提前 ...

  10. 2019-2020-2 《网络对抗技术》Exp0 环境搭建-Kali Linux 的安装

    2019-2020-2 20175334 环境搭建-Kali Linux 的安装 一.Kali的下载与安装 在Kali官网中下载镜像文件 打开Vmware开始创建新虚拟机 选择镜像文件 选择操作系统 ...