DFS 序/欧拉序的应用(持续更新)

子树相关的应用

由于子树的 dfs 序是连续的,所以很容易得到子树的信息。

树上启发式合并

用于删掉轻子树的信息

vector<int> bch(n, -1);
int cur_big=-1;
auto get_big = [&](auto &dfs, int u, int p) -> int {
    int sz = 1, mx = 0;
    for (auto v : g[u]) {
        if (v == p) continue;
        int csz = dfs(dfs, v, u);
        if (csz > mx) mx = csz, bch[u] = v;
        sz += csz;
    }
    return sz;
};
auto add=[&](auto& slf, int u, int p, int x) -> void {
    // update info of u here
    for (auto v : g[u]) {
        if (v==p || v==cur_big) continue;
        slf(slf, v, u, x);
    }
};
auto dfs = [&](auto &dfs, int u, int pa, bool keep) -> void {
    int big = bch[u];
    for (auto v : g[u])
        if (v != pa && v != big)
            dfs(dfs, v, u, 0);
    if (big != -1) {
        dfs(dfs, big, u, 1);
        cur_big=big;
    }
    add(add, u, pa, 1);
    // now you get all the info of subtree of u, answer queries about u here.
    cur_big=-1;
    if (!keep) add(add, u, pa, -1);
};
 

利用二分查询子树信息

如果查询的信息是类似于子树中有多少个节点满足一定条件,比如:有多少个节点的颜色为 x,此时我们可以为每个颜色开一个数组存,并且在 dfs 的时候将每个节点放入对应数组。由于子树的 dfs 序是连续的,在数组中的节点也是连续的,所以我们可以通过子树的根节点的进出时间戳,利用二分得到子树区间的长度。

练习题:

ABC202 E

路径相关应用

如果信息是可逆的,比如说求和,我们可以结合欧拉序,第一次访问节点的时候在序列中放入正值,访问结束之后放入负值,这样不在 dfs 栈中的节点就会被抵消掉。总的来说,假设要求的路径是从 u 到 v(v 是 u 的祖先,如果不是就拆成u->lca(u, v)v->lca(u, v)两条路径),那么路径和就是序列中in[v]in[u]的和。