将树线性化为数组并回答" sum"查询路径

时间:2016-07-23 06:56:30

标签: algorithm tree fenwick-tree

问题是由codechef中的travtree问题引起的。在editorial中,他们建议通过在DFS遍历中为每个节点记录其发现和退出时间,将树线性化为数组。现在,我们可以快速回答有关sum subtree的查询 - 通过汇总该节点的细分[discovery time, exit time]中发生的事件。 (我们使用Fenwick树快速回答这些问题。)

但是,要解决这个问题,我们还需要快速回答sum path个问题。那就是 - 总结a, b之间最短路径上发生的事件。怎么可能?他们给出的答案是:

对于每个有趣的事件,他们都会更新:

    update(BT2,event_node,1);
    update(BT2,out[event_node],-1);

现在sum path(a,b)就是这样:

    int l = lca(a,b);
    ans = query(BT2,a) + query(BT2,b) - query(BT2,l) -  (l==1  ? 0 : query(BT2, parent[0][l]));

其中query是前缀和。怎么回事?当您查看前缀总和直到a时,您可能会遇到许多与la之间的路径无关的节点!

1 个答案:

答案 0 :(得分:0)

为了线性化sum path查询 - 在树节点a, b之间的最短路径上发生的事件总和,我们确实必须执行以下操作:

当节点v中发生事件时,我们update(IN[v], 1)update(OUT[v], -1)IN是节点的DFS discovery timeOUT DFS exit time

现在查询将是query(IN[b]) - query(IN[a]-1)query(IN[b])是前缀sum:它从根开始,遍历树,直到达到b。请注意,对于每个节点v,我们将不在直接路径上从根传递到b,我们将发现并最终退出它。仅针对路径上的节点,我们将发现并且退出。由于我们更新的方式,这意味着我们将有效地对路径root, b(包括b)上的节点求和。

现在很清楚query(IN[a]-1)中发生了同样的事情 - 它是路径root, a上的节点总和(这次不包括a)。减去它们会给我们a, b。画一幅草图,你会自己看到它。

为了完整性,sum subtree的方法在updatequery中都有所不同。对于每个活动,您只需update(IN[v])。现在查询sum subtree(a)我们query(OUT[a]) - query(IN[a]-1)。这一次在query(OUT[a])中,我们对我们遍历的所有节点求和,直到我们发现a,然后a中的所有节点都为子树,直到我们退出它为止。现在我们减去query(IN[a] - 1) - 所有节点,直到我们发现a。我们只剩下a子树。