树的DFS序

image

例题:P3459 [POI2007] MEG-Megalopolis

给定一棵 \(n\) 个节点的树,根节点为 \(1\),开始每条边边权为 \(1\)。有 \(m+n-1\) 次操作,每次修改操作使得某条边边权为 \(0\),每次查询操作询问 \(1\) 到某个点的边权和。
数据范围:\(n \le 250000\)

如果从 DFS 序列的角度考虑,将每个节点在 DFS 中的第一个出现位置看作 +1,第二个位置看作 -1,则每次查询相当于查询序列的前缀和,而修改操作相当于对该条边的子节点在 DFS 序列中两次出现的位置做单点更新。

#include <cstdio>
#include <vector>
using std::vector;
const int N = 250005;
vector<int> tree[N];
int n, in[N], out[N], idx, bit[N * 2];
char op[5];
int lowbit(int x) {
    return x & -x;
}
void update(int x, int d) {
    while (x <= 2 * n) {
        bit[x] += d; x += lowbit(x);
    }
}
int query(int x) {
    int res = 0;
    while (x > 0) {
        res += bit[x];
        x -= lowbit(x);
    }
    return res;
}
void dfs(int u, int fa) {
    idx++; in[u] = idx;
    update(idx, 1);
    for (int v : tree[u]) {
        if (v == fa) continue;
        dfs(v, u);
    }
    idx++; out[u] = idx;
    update(idx, -1);
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int a, b; scanf("%d%d", &a, &b);
        tree[a].push_back(b); tree[b].push_back(a);
    }
    dfs(1, 0);
    int m; scanf("%d", &m);
    for (int i = 1; i <= n + m - 1; i++) {
        scanf("%s", op);
        if (op[0] == 'A') {
            int x, y; scanf("%d%d", &x, &y);
            int z = in[x] < in[y] ? y : x;
            update(in[z], -1); update(out[z], 1);
        } else {
            int x; scanf("%d", &x);
            printf("%d\n", query(in[x]) - 1);
        }
    }
    return 0;
}
posted @ 2024-06-09 21:44  RonChen  阅读(15)  评论(0编辑  收藏  举报