这道线段树的题目真的是超级酸爽!!!
大概题意是这样的,输入1,x,y代表输出x~y的最大值。2,x,y代表输出x~y这段区间的总和。0,x,y,t代表将x~y这段区间中值更改为min(a[i],t)。难点就在第三种情况。可以看出,数据范围10^6,普通线段树的算法解决,区间更新的算法解决不了,因为有的修改有的不改,但是递归到叶子进行修改肯定超时。这时就诞生出了很麻烦的感觉。于是题解大法由此诞生。感觉这种方法超级炫酷了,至少我没看题解的话就不会想到。
就是这样想。首先是这样的,线段树的特点就是维护某一段的特征,那么这道题的目的是求一段区间的max和sum,在更新过程中max是很容易就可以维护的。在更新的时候,很显然,如果这段区间的最大值max都比t要小,那么这段肯定就不用再被修改了,直接return就好了;另一种情况就是有的大,有的小,那么我们想到,线段树是依次向下分支找寻,能不能简单点,利用前边着一个结论呢。由此我们就想到可以维护一个最大值max和次大值second,当 t 比 max 小,但是比 second 大的时候,此时最大值max就要被替换成 t ,而且无需再往下进行更新了,因为没有必要了,直接return就好了;否则的话就要pushdown,让当前id的左右子树的特征(当前id区间的max【id】,second【id】,sum【id】,以及最大值的个数geshu[i])进行修改。在pushdown的时候,reuturn到了适合的id后,我们再pushup,因为id的特征变化是由下边两个所决定的,所以一定要进行这一步操作。这样事实上该修改的特征值都修改了,也是对lazy的一种用法。然后求最大值的时候一定要pushdown,不明白的话就研究一下lazy标记。然后就是正常的查最大值,和了。
还有就是求和的时候,简单方法就是算出最大值的个数,然后进行计算。具体看代码
ps:这道题中间有种种bug,其中在更新次大值的时候,极其容易将mx【id*2】和mx【id*2+1】进行大小比较,小的那一个作为次大值。但是事实上这样子是错误的,因为很可能mx大的,但是次大值se也比另一个mx要大,所以要都比较一边。
还有一个易错的地方,就是因为给的数据太大了,在计算sun的时候,sum[id]=sum[id]-geshu[id]*(mx[id]-t);将括号拆开写反而会WA ,因为超longlong了,这个地方也算是一个坑吧,我深陷此坑~
代码:
#include<bits/stdc+