【模板】线段树 3
题目链接:luogu P6242
题目大意
给你一个数组,然后要你维护一些东西:
区间加值,区间取最小值,区间求和,区间求最大值,区间求每个位置的历史最大值的最大值。
思路
这题的难点在于你操作二取最小值是无法用普通的线段树维护区间和的。
所以就要用到吉司机线段树。
它主要是通过维护第一大和第二大这两个东西,如果大于等于第一个就肯定无法更新,如果大于第二个就只会更新第一大,就弄就好了,否则就递归下去更新。
然后开始讲如何维护:
l s x , r s x ls_x,rs_x lsx,rsx:左右儿子
s u m x sum_x sumx:区间权值和
m a x a x maxa_x maxax:区间最大数
s e c x sec_x secx:区间第二大数
c n t x cnt_x cntx:区间最大数的个数
m a x b x maxb_x maxbx:区间历史最大数
a d d _ a x add\_a_x add_ax:区间最大值的加法的懒标记
a d d _ a 1 x add\_a1_x add_a1x:区间的不是最大值的加法的懒标记(因为你要么递归下去搞,要么就搞最大值,所以可以这么维护)
a d d _ b x , a d d _ b 1 x add\_b_x,add\_b1_x add_bx,add_b1x:同理,不过这个是历史最大值和历史非最大值的懒标记。
然后你考虑怎么维护:
首先是上传: m a x a , m a x b maxa,maxb maxa,maxb 直接取最大值, s u m sum sum 直接加起来, s e c , c n t sec,cnt sec,cnt 稍微复杂一点就分类讨论一下即可。
然后是下传:考虑那边是最大值就把下传的最大给它的最大,否则它的最大是这个的非最大(两边的非最大自然都是非最大)
至于怎么给,就是这个线段树的一个难点了。
首先全部加上最大加的乘最大的个数和非最大加的和非最大的个数(非最大的个数用全部减去最大个数)。
然后历史最大要加的加上历史要加的,懒标记也要加上各自的,然后反正就是各自加各自的,具体可以看看这段代码:
void update(int now, int k1, int k2, int k3, int k4