我对数组 A 有 n 元素的更新和查询。
我有两种类型的查询:
type 1(Update):给定x,递减数组A中值大于或等于x的所有元素的值。
type 2(Query):Given(l,r,x),找到数组A中第x个最小的元素,其值介于l和r之间(包括两者)。
除了蛮力之外我没有更好的解决方案,而且可能和O(q * n)一样昂贵。有没有最佳解决方案? 数组A的元素可以大到10 ^ 18。
答案 0 :(得分:1)
我想到的数据结构是自平衡二叉树的增强变体,例如AA树。除了普通成员之外,每个节点还存储一个隐式应用于其后代的递减计数。而不是自己更改数字,以查看节点的最终值,从每个祖先节点中减去减量计数。每个节点还保持其后代的计数。
更新包括通过树的绑定搜索(复杂度O(log n)
),并递增O(log n)
个节点的递减计数。在某些情况下,您还必须将绑定下方的元素移动到该树的下方(因为它们不再小于所有元素,这要归功于减量),这也是O(log n)
。 (请注意,最后一位需要进行一些棘手的后续更新,但我认为它不会影响整体界限。)
"查询"操作简单;二进制搜索以查找l
(r
对操作AFAICT不重要)然后使用descendant-count加速查找该范围内的第k个最小值O(log k)
因此,假设您不计算构建初始树的O(log n)
时间,则两个操作都有时间O(q*log n)
,总时间为O(n*log n)
。
答案 1 :(得分:0)
没有比以O(n)
更快的速度运行每个描述的查询更好的解决方案,其中n是数组元素的数量,在描述问题时始终在未排序的数组上。这是因为您必须考虑数组中的每个元素以进行查询。问题是您没有关于数据的信息,因此您永远不会知道在哪里检查以加快速度。
如果您要进行大量查询,可以通过对数组进行排序并对其进行排序来进行一些优化。排序最初将采用O(n log(n))
(Quicksort,Mergesort),它允许您使用修改后的二进制搜索在O(log(n))
(或最差情况O(n)
)中执行查询(查找第一个最小元素)你的范围,然后采取下一个x元素)。 (如果你使用像qsort这样的库类型,你会排序类似于1.3 nlog(n),这非常好)
它还允许您更快地执行更新,因为您可以再次使用BSearch来获取您要查找的值。这里有关数据的知识非常重要。如果你的减量不会改变订单(检查边界案例元素),那么从长远来看这更有效。
如果您的数组已排序,您也可以通过仅考虑第一个元素左侧的元素大于或等于x来有效地排序Q1。如果这些元素中的一些现在比你的一些元素大,那么你可以找到它们之间的边界,并在Q1之后在较小和较大区域之间进行交换(智能排序,使用你对数据的信息)。
如果您不能对数据进行排序(出于图形目的等),那么线性时间是您所希望的最佳时间。如果您的阵列很小,也不需要排序,它将是过度杀伤而不会带来显着的改进。老实说,线性时间在现代计算机上确实很好。