影魔
这一道题目有一个非常重要的思想,就是确定一个基准
就像计数题目一样,我们将一个区间确定一个基准,我们一般用端点作为基准,然而这道题目却行不通
但是这道题目的题干却一直提到最大值,所以我们以一个区间的最大值为基准,显然可以唯一确定
那么就不难确定一个区间\([a,b]\),以\((a,b)\)的最大值为基准
所以我们对每一个数,求出它左边和右边距离他最近的又比他大的数(单调栈)
然后按照题解处理即可(看到无修改,可以想到离线)
解释一下他这个处理方法,考虑\([l,r]\)这个区间所有点的贡献所包含的类型只有题解中说到的三种类型。对于题解中提到的\(sum_2\),包含所有三种类型的和,然而此时有些第三种类型产生的贡献我们是不想要的(左端点小于\(l\)),于是我们只用在进入\(l\)之前统计一下这些端点所产生的贡献就好了(这个思想跟“校门外的树”一样)
也可以用类似于HH的项链的方法,我们的代码用的是这个方法
这两种方法都要记下来,我们对第二种方法更加熟悉,然而第一种方法也是有应用的,比如在某些子树的统计题目里面:进入子树之前记录数组值,递归完之后准备出去的时候再记录数组值,相减即得答案
update 2024.5.16
我们也可以以区间的端点作为基准,下面以第一类贡献为例讨论
我们仍然像上面这样处理处\(L\)和\(R\)数组,然后从左往右扫描,当我们扫描到\(r\)这个点的时候,有可能产生贡献的区间左端点的范围就是\([r-L[r],r-1]\),我们只用再在这些点中统计出有多少点\(i\)满足\(i+R[i]≥r\)即可
如果我们已经维护好了一个序列,若第\(i\)个位置的值为,那么直接用树状数组查询前缀和就好了;在我们从\(r\)变成\(r+1\)的时候,我们只用把所有满足\(i+R[i]=r\)的位置的值变为\(0\)就好了,并且将\([r+1,r+1+R[r+1]-1]\)的位置全部变\(1\),也可以用树状数组做到
还有一个问题,就是这道题目的询问是某一个区间,此时就要像题解那样子处理:对于一个区间\([l,r]\),在扫描到\(l-1\)的时候统计此时区间\([l,r]\)的总和,之后减掉就好了
以上做法有问题,可以想一下应该怎么做