当前位置:首页 > 数据结构 > 线段树 > 正文
VIJOS1083小白逛公园
318+

题目大意:一个长度不超过50万的数列,需要进行单点修改以及求区间最大连续和!

描述

小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a、b两个公园)选择**连续**的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。

那么,就请你来帮小白选择公园吧。

格式

输入格式

第一行,两个整数N和M,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。

接下来N行,每行一个整数,依次给出小白 开始时对公园的打分。

接下来M行,每行三个整数。第一个整数K,1或2。K=1表示,小新要带小白出去玩,接下来的两个整数a和b给出了选择公园的范围(1≤a,b≤N, a可以大于b!);K=2表示,小白改变了对某个公园的打分,接下来的两个整数p和s,表示小白对第p个公园的打分变成了s(1≤p≤N)。

其中,1≤N≤500 000,1≤M≤100 000,所有打分都是绝对值不超过1000的整数。

输出格式

小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。

样例1

样例输入1

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 2 3

样例输出1

2
-1

限制

各个测试点2s

解题思路

区间求值可以用线段树维护,下面考虑线段的含义:求区间最大连续和,那么d就记录区间最大连续和。那么区间最大连续和需要怎么求呢?怎么由儿子结点更新到父亲结点呢?

一个区间c,分成2部分a和b,那么c的最大连续和可以是只有a的,也可以是只有b的,还可以是a和b都有。包含a和b,需要用到包含a末尾的最大连续和以及包含b开头的最大连续和;而求开头结尾的最大连续和,需要用到区间的和。因此一个结点除了需要记录最大连续和d以外,还需要记录区间和s、前面的最大连续q和以及后面的最大连续和h。

单点修改时,d、s、q、h都直接修改就行,因为区间长度就是1。两段合并到一段时,请见代码hb函数,其中和区间和s等于儿子之和;前面连续和q等于左儿子的前面连续和或者左儿子的和加上右儿子的前面连续和(保证是做端点开头,而且连续);后面连续和h同理;区间最大连续和先去左右儿子的区间最大连续和,如果左儿子后面连续和加上右儿子前面连续和更大,则区更大的值。(建议画图理解)

查询的时候,不能直接返回最大连续和,因为左右两半的最大连续和并不足够,还需要看一下中间部分,故左边和右边得到的都是线段,返回的是结构体。如果两半都有,则需要合并,否则只需要返回左边或者右边的线段。

程序实现

数组写法:查询的时候动态开点,存储中间过程的小段合并。

结构体写法:查询函数返回的是结构体,最后结果就是结构体的d值。注意,单点修改21-23行,两边都有才往上更新,否则需要动态开个空点(读入n个数后,会全部自动往上更新)。

更多

About

坚决不Copy代码!

本文标签:,,,,,

VIJOS1083小白逛公园:等您坐沙发呢!

发表评论

😉😐😡😈🙂😯🙁🙄😛😳😮mrgreen.png😆💡😀👿😥😎😕

快捷键:Ctrl+Enter