DFS序就是将树形结构转化为线性结构,用dfs遍历一遍这棵树,进入到x节点有一个in时间戳,递归退出时有一个out
时间戳,x节点的两个时间戳之间遍历到的点,就是根为x的子树的所有节点,他们的dfs进入时间戳是递增的。同时两个时间戳构成了一个区间,x节点在这段区间的最左端,这个区间就是一棵根节点为x的子树,对于区间的操作就是其他维护方式的应用了。
模板题:
POJ3321
题意:给一个普通树(不是二叉树),并且已经编号,每个结点为1或0,有两种操作,对单个结点修改和查询一个结点的子树的所有结点的值。
思路:dfs序+树状数组
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const int N = 2e5 + 10;
int n, m, h[N], cnt, in[N], out[N], dfn, vis[N], t[N];
struct node {
int v, nt;
} no[N];
void add(int u, int v) {
no[cnt] = node{v, h[u]};
h[u] = cnt++;
}
void dfs(int u, int fa) {
in[u] = ++dfn;
for(int i = h[u]; ~i; i = no[i].nt) {
int v = no[i].v;
if(v != fa)
dfs(v, u);
}
out[u] = dfn;
}
void update(int x, int num) {
while(x <= n) {
t[x] += num;
x += lowbit(x);
}
}
int query(int x) {
int ans = 0;
while(x > 0) {
ans += t[x];
x -= lowbit(x);
}
return ans;
}
int main() {
memset(h, -1, sizeof h);
scanf("%d", &n);
for(int i = 1; i <= n; i++)
update(i, 1);
for(int u, v, i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
dfs(1, 0);
scanf("%d", &m);
char c;
for(int d, i = 1; i <= m; i++) {
scanf(" %c %d", &c, &d);
if(c == 'Q')
printf("%d\n", query(out[d]) - query(in[d] - 1));
else {
if(!vis[d])
update(in[d], -1), vis[d] = 1;
else
update(in[d], 1), vis[d] = 0;
}
}
return 0;
}