树的DFS序
例题: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;
}