天使玩偶

来解释一下许多细节和疑问

在简化问题考虑左下中,为什么按照横坐标从小到大排序就好了?不应该还要以纵坐标为第二关键字排序吗?不然有可能某次询问(x,y)的下面一个点(xi,yi)(yi<y))还没有更新就轮到(x,y)了,这就无法统计了啊?

答:如果单独考虑左下的话,这个做法确实有问题,也的确需要以纵坐标为第二关键字排序。但是如果考虑四个方向的话,只以横坐标排序就是没问题的,上面说的这种情况会在其他时候被统计到。比如就说上面说的这种情况,那么当这种情况出现的时候,我们左下的确是无法统计(x,y)的,但是轮到统计右下的时候,我们此时(相对于左下)是倒着循环的,之前在左下没有被先添加进去的(xi,yi)说明他在序列中的位置在(x,y)之后,所以此时就一定会被先添加,然后就会被统计了

为什么可以用树状数组统计没有可加性的最大值?

答:我们考虑一下为什么树状数组不能统计最大值。翻到蓝书的P203,看看那个树状数组的图,想一下如果我们没有修改操作而是只有初始的序列,那么我们如何更新树状数组?答案当然就是对每一个树状数组,对他的所有儿子取最大值(比如c[16]=max(c[8],c[12],c[14],c[15],a[16])),没有修改操作的情况下,这个显然是对的(c[i]维护的就是[ilowbit(i)+1,i]的最大值)。那我们现在加入修改操作。如果我们将a[i]修改为k,用最暴力的方法,如果更新c数组?这里不太好用文字说明,我先举一个例子。比如修改a[12],那我们先找到c[12],令c[12]=max(c[10],c[11],k),然后再找到c[16],令c[16]=max(c[8],c[12],c[14],c[15],a[16])。所以就是找到对应位置的树状数组,然后一路往上,对经过的每一个节点,都要重新对其所有儿子取最大值。之所以要这么做,是因为有可能会出现一种情况,比如c[12]刚好等于a[12],而a[12]恰好又是[9,12]严格最大值,而我们修改的k刚好严格小于a[12],这下就没办法直接说明c[12]最新的最小值了,所以我们必须比较暴力的更新。然而对于一般的问题来说,即使我们暴力更新了,我们也没办法查询[l,r]的最大值,因为最大值是没有可加性的。但是回到这一道题目,可以证明,四个方向都不会出现上述说明的情况,比如统计左下方的时候,扫描到一个点(xi,yi),由于我们按照了x从小到大排序,此时修改序列的a[yi],一定能被修改成功(也就是上文说的k一定大于a[yi]),于是就不会出现上文说的情况,所以就可以像代码一样区间更新。而这道题目刚好又是只用查询[0,y]的最大值,所以即使不满足可加性问题也不大

为什么统计左上的时候修改的位置要变为106yi

答:就像上文提到的,这里之所以能用树状数组是因为我们不用满足可加性,查询的是[0,y],这里为了继续利用这个性质,由于我们此时要查询的是[y,106],所以我们要把他倒过来统计

最后提一嘴时间复杂度的计算,一共有log(N+M)层,每层的总时间复杂度(N+M)log(N+M),所以时间复杂度为O((N+M)log2(N+M))

代码就看打卡代码,写的很好,学习简化代码的技巧

另外这道题目可以转化成三维偏序问题,加入时间维即可,也就是二维偏序+动态修改

posted @   最爱丁珰  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示