这可以用段树正确建模吗?

时间:2017-07-19 18:54:02

标签: algorithm segment-tree

我正在处理的问题需要在数组上处理多个查询(数组的大小小于10k,最大的元素肯定小于10^9)。

查询由两个整数组成,其中一个必须找到具有相同整数的子数组的总数。最多可能有5 * 10^5次查询。

例如,给定数组[1, 2, 1]和查询1 2,我们发现有两个子数组具有相同的12计数,即{{1 }和[1, 2]

我最初的方法是使用动态编程来构建地图,例如[2, 1]。我会以类似的方式使用它来使用前缀和,但是频率会累积。

构建此地图需要我memo[i][j] = the number of times the number i appears in the array, until index j。对于每个查询,我会针对每个间隔执行O(n^2)处理并递增答案。这导致O(1) [O((q + 1)n * (n - 1) / 2))是查询数量]的复杂性,也就是说q,但我也想强调这个令人生畏的常数因素。

经过一些重新安排后,我试图找出是否有办法确定每个子阵列中每个元素的频率计数。我强烈地感觉到这个问题是关于细分树的问题,而且我一直在努力想出一个合适的模型,这是我唯一能想到的。

然而,考虑到组合节点拥有如此大量信息的复杂性,我的方法在这种情况下似乎并不太有用,更不用说内存开销了。

如何有效地解决这个问题?

1 个答案:

答案 0 :(得分:1)

想法1

通过计算累积计数差异的频率计数,您可以将每个查询的时间从O(n ^ 2)减少到O(n):

from collections import defaultdict

def query(A,a,b):
    t = 0
    freq = defaultdict(int)
    freq[0] = 1
    for x in A:
        if x==a:
            t+=1
        elif x==b:
            t-=1
        freq[t] += 1
    return sum(count*(count-1)/2 for count in freq.values())

print query([1,2,1],1,2)

这个想法是t表示两个元素的计数之间的总差异。

如果我们在阵列中找到两个具有相同总差异的位置,我们可以得出结论,这些位置之间的子阵列必须具有相同的数字。

表达式count*(count-1)/2只是计算从计数中选择具有相同差异的两个位置的方式的数量。

实施例

例如,假设我们有数组[1,1,1,2,2,2]。累积差异的值(1' s的数量为2')将为:

0,1,2,3,2,1,0

每对具有相同数字的对应于具有相同计数的子阵列。例如看着这对2,我们发现从位置2到位置4的范围具有相同的数量。

创意2

如果仍然不够快,您可以优化查询功能以快速跳过所有不等于a或b的元素。例如,您可以为包含该元素的所有位置的每个元素值准备一个列表。

获得此列表后,您可以立即跳转到a或b的下一个位置。对于所有中间值,我们知道差异不会改变,因此您可以通过跳过的元素的数量更新频率(而不是总是仅向计数添加1)。