对树中路径的范围查询
Range Queries on a path in a tree
我在一次比赛中遇到了这个问题(现在已经结束了),我想不出一个省时的算法。
给你一个 N (<=10^5) 节点的根树。最初所有节点的值均为 0.树将有 M 个更新 (<=10^5),其形式为
添加 x y – 将 y 添加到节点 x 。
添加 x y – 将 y 添加到 x,x 的父级,x 的父级直到根。
之后会有 Q 查询 (<=10^5) 查询,其中将要求您给出节点的值或根植于该节点的子树的总和。
我做了什么:-
首先,我尝试了根据操作更新每个节点的朴素算法,但显然这很耗时。
我也想过使用分段树和延迟传播,但想不出正确的方法。
任何帮助不胜感激,谢谢!
首先,构建一个图表,让孩子指向他们的父母。之后,解析所有更新,并将添加和添加的总和分别存储在树的每个节点中。您的节点应具有以下变量:
sum_add : the sum of all the Add of this node
sum_add_up : the sum of all the AddUp of this node
subtree_sum : the sum of the subtree. Initialize with 0 by now.
现在,使用拓扑顺序横向你的图,即,如果一个节点的所有子节点都已经处理完毕,你才会处理它,这需要 O(N)。现在让我定义流程函数。
process(V) {
V.sum_add_up = V.sum_add_up + sum(sum_add_up of all V.children)
V.subtree_sum = V.sum_add + V.sum_add_up + sum(subtree_sum of all V.children)
}
现在你可以回答 O(1) 中的所有查询。对节点V
值的查询是V.sum_add + V.sum_add_up
,而对V
的子树的查询只是V.subtree_sum
。
这是一个芬威克树,为了解决这类问题,你必须在树上执行拓扑排序并计算每个节点的子节点数量。
0
/
1 2
/
3 4
索引: [0 1,2,3,4]儿童: [4,2,0,0,0]使用拓扑,您将获得此向量 0 1 3 4 2 您需要反转它:
fenwick Pos: [0,1,2,3,4]
vector values:[2,4,3,1,0]
pos: [5,3,0,2,1]
使用泛威树您可以执行2种查询,更新查询,范围和查询当您需要更新仅一个索引调用update(pos[index], y)
时,您必须减少所有下一个值,update(pos[index]+1, -y)
当您需要更新所有家长时,请致电update(pos[index], y)
和update(pos[index] + childrens[index] + 1, -y);
要知道仓位的值,您需要在 POS[index] 上调用范围总和查询
我认为这个问题只是二叉搜索树的直接应用,它对插入和查询都有平均案例成本(n 次随机操作后)O(1.39log(n))
。
您所要做的就是递归添加新节点并同时更新值和求和。
实现也相当简单(对不起 C#),例如对于 Add()
(AddUp()
相似 - 每次转到左侧或右侧子树时都会增加值):
public void Add(int key, int value)
{
Root = Add(Root, key, value);
}
private Node Add(Node node, int key, int value)
{
if (node == null)
{
node = new Node(key, value, value);
}
if (key < node.Key)
{
node.Left = Add(node.Left, key, value);
}
else if (key > node.Key)
{
node.Right = Add(node.Right, key, value);
}
else
{
node.Value = value;
}
node.Sum = Sum(node.Left) + Sum(node.Right) + node.Value;
return node;
}
对于我机器上的 100000 个数字,这转换为以下数字:
Added(up) 100000 values in: 213 ms, 831985 ticks
Got 100000 values in: 86 ms, 337072 ticks
对于 100 万个数字:
Added(up) 1000000 values in: 3127 ms, 12211606 ticks
Got 1000000 values in: 1244 ms, 4857733 ticks
这个时间够有效吗?您可以在此处尝试完整的代码。
- Mongodb c++驱动程序:如何查询元素的数组
- 为什么在全局范围内使用"extern int a"似乎不行?
- 查询SQLite数据库中的日期
- 尝试通过多个向量访问变量时,向量下标超出范围
- 错误:未在此范围内声明'reverse'
- 正在将指针转换为范围
- 使用std::transform将一个范围的元素添加到另一个范围中
- 在 c++ 中解决段树以外的范围查询的有效方法是什么?
- 对于多个查询,查找在 l 到 r 范围内具有相同元素的最长公共子数组
- MongoDB:跨日期范围的查询
- 对树中路径的范围查询
- C++MySql连接器-查询的结果超出范围
- 减少具有未排序时间范围的表中的查询时间
- C++数据结构的时间范围查询
- 如何查询范围中的任何位是否在 C++ std::bitset 中设置
- 使用 Firedac 进行 MongoDB 的时间范围查询
- 数组上的范围最小查询
- mongodbc++查询一天的范围
- c++中任何好的范围查询库(使用K-D树,四叉树或r语言 - 树)
- 范围最小查询