zoukankan      html  css  js  c++  java
  • 一些区间无重和问题

    区间无重和问题:

    问题描述:

    对于一个有序数组 (a[1…n]) ,希望(O(lg n))地查询任意区间 ([l, r]) 中元素之和,且重复元素只加一次。

    解决方法:

    对于每个点上的元素,我们额外维护一个前向指针 (prev),指向它左方最近一个与之具有相同值的元素。

    有了前向指针,对于任一区间([l, r]),显然只需遍历一遍,将所有满足 (prev < l) 的元素累加,即可得到答案。

    接下来思考如何优化这个过程,观察答案的式子:

    [sum_{prev_i < l} {a_i} ]

    我们发现,如果将结点按照 (prev) 关键字排序,那么答案就是一个前缀和,因此我们可以在排序后预处理出前缀和,然后二分查找得到答案。

    还有区间查询的问题未解决,自然想到线段树:对树上每一个结点作预处理,将其对应区间内的元素进行排序并记录前缀和;对区间([L, R])查询时,只需对线段树上所有子区间二分查找出 (prev < L) 的前缀和,然后合并答案即可。时间复杂度(O(n lg^2n)),空间复杂度(O(nlg n))

    缺点:不支持在线增删


    重新考虑这个问题,我们要在线地查询

    [sum_{prev_i < L} sum_{L leq i leq R} a_i ]

    直接一个树状数组套线段树就可以解决了,写起来甚至比上一个方法简单)

    有一些题目,层层剥开后,就发现就是一个无重和/积问题。
    另外,将 (a_i) 设置为 (1),答案就是区间中去重元素个数。

    例题

    例1:codeforces 1422 F
    刚才说的第一种方法就是从这学的。。
    问题描述:给一个正整数序列,每个元素不超过2*1e5,强制在线查询给定区间的LCM。
    分析:在素因数分解后,若干个数的LCM即为各个素因子幂次取max,然而,素数太多了,不能这么干,真的不能吗?

    注意到 (n) 至多只有一个大于 (sqrt n) 的素因子,其余素因子都是不超过 (sqrt n) 的,所以我们先对 450 以下的素因子建立线段树维护区间最大幂次,将这些小的素因子提出后,每一位剩下的只能是 1 或者 素数。问题就转化为对一个素数序列动态查询区间LCM了,而素数们的LCM,不就是去重积吗?

    例2:codeforces 1436 E
    分析:求一个有序数组的所有子段(一段连续的元素)的Mex的Mex,问题看着很吓人,不过我们首先注意到 (1 leq a_i leq n),这说明所有子段的Mex一定位于([1, n + 1])中,所以我们可以令 (x)(1) 遍历到 (n + 1),逐步检验是否存在一个子段的Mex为 (x)

    任何一个Mex为 (x) 的子段一定不包含 (x),而在不含 (x) 的条件下,子段当然越大越有可能满足条件,考虑 (x) 会将序列分为若干不含 (x) 的极大子段,只需对这些极大子段逐一验证即可,在 (x) 遍历的过程中,总共会出现 (O(n)) 个极大子段,如何快速地处理每个子段呢?

    对不含 (x) 的子段进行验证,其实就是判断它是否含有 (1)(x - 1) 的所有值,我们希望它等价于 “区间元素个数为 (x - 1)(去重) ”,为此,只需要在每次遍历完 (x) 后,再把所有值为 (x) 的元素放入树套树。这样就能 (O(lg n)) 地处理每个极大子段了。

  • 相关阅读:
    几个基本trick
    CSP2019 树上的树 口胡
    To do List
    对代码风格的探索(持续更新)
    我回来了。
    年度悲剧
    最短路
    平衡树
    线段树-模板
    jmeter断言之JSON Assertion
  • 原文地址:https://www.cnblogs.com/komeiji-green/p/13922910.html
Copyright © 2011-2022 走看看