C++ 请告诉我有效的范围Mex查询算法
关于这个问题我有个问题 问题:C++ 请告诉我有效的范围Mex查询算法,c++,algorithm,game-theory,C++,Algorithm,Game Theory,关于这个问题我有个问题 问题: 给你一个序列a[0],a[1],…,a[N-1],以及一组范围(l[i],r[i])(0>a[i]; 对于(int i=0;i>l>>r; 设置s; 对于(int j=l;j
- 给你一个序列
,以及一组范围a[0],a[1],…,a[N-1]
(l[i],r[i])(0>a[i]; 对于(int i=0;i
>l>>r; 设置s; 对于(int j=l;j
cout让我们以从左到右的方式处理查询和元素,比如
考虑到在我们的特殊情况下,对树的所有查询都是前缀和查询,for (int i = 0; i < N; ++i) { // 1. Add a[i] to all internal data structures // 2. Calculate answers for all queries q such that r[q] == i }
始终等于from
,因此,对子级的一个调用总是返回一个微不足道的答案(0
或已计算的0
)。因此,不要执行sum
查询到二维树在二进制搜索算法中,我们可以实现一个特殊的搜索过程,非常类似于这个O(log N)
查询。它应该首先获取左个子节点的值(因为它已经计算了get
),然后检查我们要查找的节点是否在左边(此总和小于左子树中的叶数)并根据此信息向左或向右移动。此方法将进一步优化对O(1)
时间的查询(因为它现在是一个树操作),从而在时间和空间上产生O(log^2 N)
O((N+Q)log^2 N))的复杂性 不确定此解决方案对于
和Q
到N
是否足够快,但它可能会进一步优化。以下是10^5
解决方案:O((Q+N)log N)
- 让我们从左到右遍历数组中的所有位置,并将每个值的最后出现次数存储在段树中(段树应在每个节点中存储最小值)
- 添加
-第个编号后,我们可以回答右边框等于i
的所有查询i
- 答案是最小的值
就这样 下面是一些伪代码:
,这样x
。我们可以从根开始向下搜索段树(如果左侧子项中的最小值小于last[x]
,我们就到那里。否则,我们就到右侧子项)l
查找较小的函数如下所示:tree = new SegmentTree() // A minimum segment tree with -1 in each position for i = 0 .. n - 1 tree.put(a[i], i) for all queries with r = i ans for this query = tree.findFirstSmaller(l)
class Tree { int l, r; // begin and end of the interval represented by this vertex int sum; // already calculated sum int overriden; // value of override or special constant Tree *left, *right; // pointers to children } // returns sum of the part of this subtree that lies between from and to int Tree::get(int from, int to) { if (from > r || to < l) // no intersection { return 0; } if (l <= from && to <= r) // whole subtree lies within the interval { return sum; } if (overriden != NO_OVERRIDE) // should push override to children { left->overriden = right->overriden = overriden; left->sum = right->sum = (r - l) / 2 * overriden; overriden = NO_OVERRIDE; } return left->get(from, to) + right->get(from, to); // split to 2 queries }
int findFirstSmaller(node, value) if node.isLeaf() return node.position() if node.leftChild.minimum < value return findFirstSmaller(node.leftChild, value) return findFirstSmaller(node.rightChild)
int findFirstSmaller(节点,值) if node.isLeaf() 返回node.position() 如果node.leftChild.minimum<值 返回findFirstSmaller(node.leftChild,值) return findFirstSmaller(node.rightChild)
这个解决方案很容易编码(您只需要点更新和上面显示的
函数,我确信它对于给定的约束足够快。在处理第一个查询之前,您知道所有查询,对吗?我的意思是,批处理算法是可以的,您不需要在线回答。Fline算法是可以的。是这样吗分段树的rt排序问题?@Arunmu sqrt分解可以,分段树也可以,如果你能为segtree求解的话。你说O(N^2)很慢……你说的是对一个范围的求值还是对所有范围的求值?对于后者,O(N^2)事实上可能没那么糟糕…希望我的答案可以理解。如果有不清楚的地方,请发表评论。行扫描算法。我今天没有时间,所以我明天会检查。@square1001是的,扫描行+二维范围树+二进制搜索或树的自定义findFisrtSmaller
int findFirstSmaller(node, value) if node.isLeaf() return node.position() if node.leftChild.minimum < value return findFirstSmaller(node.leftChild, value) return findFirstSmaller(node.rightChild)