\[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)\) 的 贪心分治 做法,我们讨论的重点是 分治 做法。

\(~\)

假设当前需求解最大子段和的区间是 \([l,r]\) ,令 \(mid=\left\lfloor\dfrac{l+r}{2}\right\rfloor\)

我们套路地把 \([l,r]\) 分成 \([l,mid]\) 和 \([mid+1,r]\) ,来进行分治求解:

\(~\)

首先对于形如 \([l,l]\) 的区间,就十分好处理了,这里不多说。

\(~\)

接下来,考虑下最大子段和满不满足 区间可加性 ?(\([l,mid]\) 和 \([mid+1,r]\) 的最大子段和能否推至 \([l,r]\))

显然,只维护一个最大子段和,对 左子区间右子区间 的最大子段和取个 \(\max\) 是不能维护最大子段和的,因为其漏掉了 最大子段和同时包含左子区间和右子区间 的情况。

那么对于剩下的这一种情况,它是必定经过中点 \(mid\) 的,那这种情况的最大段就是 左子区间从右端点向左走的最大段右子区间从左端点向右走的最大段 的并集,其值为 左子区间的后缀最大子段和 \(+\) 右子区间的前缀最大字段和

那我们再维护 前 \(/\) 后 缀最大子段和 ,对其三者取 \(\max\) ,最大子段和就满足区间可加性了。

维护 前 \(/\) 后 缀最大子段和 依旧可以分成 经过 \(mid\) \(/\) 不经过 \(mid\) 来讨论。

以前缀最大子段和为例,若经过 \(mid\) ,则最大段为 左子区间右子区间从左端点向右走的最大段 的并集,其值为 左子区间和 \(+\) 右子区间的前缀最大子段和 ;若不经过 \(mid\) ,则最大段为 左子区间从左端点向右走的最大段 。二者取个 \(\max\) 即可。后缀最大子段和同理。

那我们再维护个 区间和 ,那 最大子段和前 \(/\) 后 缀最大子段和 就都满足区间可加性了。

至于 区间和 \(......\) ,这玩意直接加就行了。

(上述内容大家可以自己画图感性理解一下

\(~\)

求解过程

约定变量:

\(sum\) : 区间和

\(lmax\) : 区间前缀最大子段和

\(rmax\) : 区间后缀最大子段和

\(wmax\) : 区间最大子段和

设函数 \(ask(l,r)\) 求的是关于区间 \([l,r]\) 的一个四元组\((\) \(sum\), \(lmax\), \(rmax\), \(wmax\) \()\)

首先有一个递归边界 \(l=r\) ,此时这四个元素均为 \(A_l\) 。

那对于一般情况,令 \(lc=ask(l,mid),rc=ask(mid+1,r)\) ,则有:

\[self.sum=lc.sum+rc.sum
\]

\[self.lmax=\max(lc.lmax,lc.sum+rc.lmax)
\]

\[self.rmax=\max(rc.rmax,rc.sum+lc.rmax)
\]

\[self.wmax=\max(lc.wmax,rc.wmax,lc.rmax+rc.lmax)
\]

此时 \(self\) 即为 \(ask(l,r)\) 。

struct data{
int sum;
int lmax;
int rmax;
int wmax;
}; data ask(int l,int r)
{
data self;
if(l==r)
{
self.sum=self.lmax=self.rmax=self.wmax=A[l];
return self;
}
int mid=(l+r)/2;
data lc=ask(l,mid),rc=ask(mid+1,r);
self.sum=lc.sum+rc.sum;
self.lmax=max(lc.lmax,lc.sum+rc.lmax);
self.rmax=max(rc.rmax,rc.sum+lc.rmax);
self.wmax=max(max(lc.wmax,rc.wmax),lc.rmax+rc.lmax);
return self;
}

\(~\)

然后你会发现,若对于每个询问都调用一次 ask(l,r) 会稳稳 T 掉

那我 bb 这么多有什么用呢

大家仔细想想,这个分治的过程像不像某个数据结构呢?

线段树?

线段树!

是的,用线段树维护,每个节点保存的是该节点所代表的区间 \([l,r]\) 的 \((\) \(sum\), \(lmax\), \(rmax\), \(wmax\) \()\) 。

剩下的都是一些线段树基本操作了。

\[Code
\]

#include<cstdio>
#include<algorithm> #define RI register int using namespace std; const int SIZE=500100; int n,m;
int a[SIZE]; struct SegmentTree{
int l,r;
int sum;
int lmax;
int rmax;
int dat;
}t[SIZE*4]; void build(int p,int l,int r)
{
t[p].l=l;t[p].r=r;
if(l==r){t[p].sum=t[p].lmax=t[p].rmax=t[p].dat=a[l];return;}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
t[p].lmax=max(t[p*2].lmax,t[p*2].sum+t[p*2+1].lmax);
t[p].rmax=max(t[p*2+1].rmax,t[p*2+1].sum+t[p*2].rmax);
t[p].dat=max(max(t[p*2].dat,t[p*2+1].dat),t[p*2].rmax+t[p*2+1].lmax);
} void change(int p,int x,int val)
{
if(t[p].l==t[p].r){t[p].sum=t[p].lmax=t[p].rmax=t[p].dat=val;return;}
int mid=(t[p].l+t[p].r)/2;
if(x<=mid)change(p*2,x,val);
else change(p*2+1,x,val);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
t[p].lmax=max(t[p*2].lmax,t[p*2].sum+t[p*2+1].lmax);
t[p].rmax=max(t[p*2+1].rmax,t[p*2+1].sum+t[p*2].rmax);
t[p].dat=max(max(t[p*2].dat,t[p*2+1].dat),t[p*2].rmax+t[p*2+1].lmax);
} SegmentTree ask(int p,int l,int r)
{
if(l<=t[p].l&&t[p].r<=r)return t[p];
int mid=(t[p].l+t[p].r)/2;
if(l<=mid&&mid<r)
{
SegmentTree lc=ask(p*2,l,r),rc=ask(p*2+1,l,r),self;
self.sum=self.lmax=self.rmax=self.dat=0;
self.sum=lc.sum+rc.sum;
self.lmax=max(lc.lmax,lc.sum+rc.lmax);
self.rmax=max(rc.rmax,rc.sum+lc.rmax);
self.dat=max(max(lc.dat,rc.dat),lc.rmax+rc.lmax);
return self;
}
if(l<=mid)
return ask(p*2,l,r);
if(mid<r)
return ask(p*2+1,l,r);
} int main()
{
scanf("%d",&n);
for(RI i=1;i<=n;i++)
scanf("%d",&a[i]); build(1,1,n); scanf("%d",&m); while(m--)
{
char op[2];
int l,r;
scanf("%s%d%d",op,&l,&r); switch(op[0])
{
case '1':{
if(l>r)swap(l,r);
printf("%d\n",ask(1,l,r).dat);
break;
} case '0':{
change(1,l,r);
break;
}
}
}
return 0;
}

\[Thanks \ for \ watching
\]

题解 SP1716 【GSS3 - Can you answer these queries III】的更多相关文章

  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 线段树

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

  3. SP1716 GSS3 - Can you answer these queries III

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

  4. 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 ...

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

    GSS3 Description 动态维护最大子段和,支持单点修改. Solution 设 \(f[i]\) 表示以 \(i\) 为结尾的最大子段和, \(g[i]\) 表示 \(1 \sim i\) ...

  6. 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 ...

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

  8. 题解【SP1716】GSS3 - Can you answer these queries III

    题目描述 You are given a sequence \(A\) of \(N (N <= 50000)\) integers between \(-10000\) and \(10000 ...

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

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

随机推荐

  1. Asp.Net Core下的开源任务调度平台ScheduleMaster

    从何说起 2017年初的时候,由于当时项目需要做了一个乞丐版定时调度系统,那时候只在单机上实现了核心的调度功能.做这个玩意之前也调研了社区中开源的解决方案,找了几个实地部署试跑了一下,其实都很不错.但 ...

  2. Atom + Texlive 配置 Latex 环境

    Atom + Texlive 配置 Latex 环境 步骤1: 安装TexliveTexlive点击 "Download" 下载,然后安装,等待安装完成即可 步骤2: 安装Atom ...

  3. 转载 css截取td里面的内容 如何固定td th的宽度

    源博客地址:http://blog.csdn.net/u011456552/article/details/53839255 效果图: 源码: <!DOCTYPE html> <ht ...

  4. Codeforces - A. Watermelon

    A. Watermelon time limit per test 1 second memory limit per test 64 megabytes input standard input o ...

  5. 图解kubernetes调度器ScheduleAlgorithm核心实现学习框架设计

    ScheduleAlgorithm是一个接口负责为pod选择一个合适的node节点,本节主要解析如何实现一个可扩展.可配置的通用算法框架来实现通用调度,如何进行算法的统一注册和构建,如何进行metad ...

  6. 通过核心API启动单个或多个scrapy爬虫

    1. 可以使用API从脚本运行Scrapy,而不是运行Scrapy的典型方法scrapy crawl:Scrapy是基于Twisted异步网络库构建的,因此需要在Twisted容器内运行它,可以通过两 ...

  7. 带限制的广搜 codeforces

    You are playing some computer game. One of its levels puts you in a maze consisting of n lines, each ...

  8. Nginx模块讲解

    Nginx模块分为:nginx官方模块.第三方模块 通过nginx -V查看编译参数,可以看到官方编译的模块 --with-compat --with-file-aio --with-threads ...

  9. Tesseract-OCR-v5.0中文识别,训练自定义字库,提高图片的识别效果

    1,下载安装Tesseract-OCR 安装,链接地址https://digi.bib.uni-mannheim.de/tesseract/ ​ 2,安装成功 tesseract -v 注意:安装后, ...

  10. 机器学习-Tensorflow之Tensor和Dataset学习

    好了,咱们今天终于进入了现阶段机器学习领域内最流行的一个框架啦——TensorFlow.对的,这款由谷歌开发的机器学习框架非常的简单易用并且得到了几乎所有主流的认可,谷歌为了推广它的这个框架甚至单独开 ...