例題: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;
}