什么是DFS序
DFS序是指对一棵树进行DFS时,每个节点被访问到的顺序。DFS序分成两个部分:进入该节点的顺序和退出该节点的顺序。
如何求DFS序
对于DFS中当前节点
1:计数++
2:进入当前节点的顺序等于当前计数
3:想所有子节点继续搜索
4:退出当前节点的序列等于当前计数
模板代码
void dfs(int t,int f){//t代表当前节点的编号,f代表父节点的编号
in[t]=++cnt;//in 进入该节点的顺序,cnt:计数
for(int i=head[t];i;i=edge[i].next){
if(edge[i].n!=f){
dfs(edge[i].n,t);
}
}
out[t]=cnt;//out:退出该节点的顺序
}
DFS的性质
某些连续的入序对应树中的节点是一条链(编号是有顺序的,且连在一起的),某节点入序和出序之间对应的节点一定在其子树中。(访问到某个节点的子树,那么该节点的入序一定是小于这个节点的子树的入序)(如果是出序那么,访问到该节点的子树,该节点的出序一定是大于或等于这个节点子树的出序)
如果一个节点的入序为2,出序为8,那么所有2~8的入序或出序是这个节点或者是这个节点的子树
DFS是有序的
例题
问题描述
给一棵含有 n 个结点的有根树,根结点为 11,编号为 i 的点有点权 ai(i∈[1,n])。现在有两种操作,格式如下:
- 1 x y:该操作表示将点x 的点权改为 y。
- 2 x:该操作表示查询以结点 x 为根的子树内的所有点的点权的异或和。
现有长度为 m 的操作序列,请对于每个第二类操作给出正确的结果。
输入格式
输入的第一行包含两个正整数n,m,用一个空格分隔。
第二行包含 n 个整数a1,a2,…,an,相邻整数之间使用一个空格分隔。
接下来 n−1 行,每行包含两个正整数 ui,vi,表示结点 ui 和 vi 之间有一条边。
接下来 m 行,每行包含一个操作。
输出格式
输出若干行,每行对应一个查询操作的答案。
样例输入
4 4
1 2 3 4
1 2
1 3
2 4
2 1
1 1 0
2 1
2 2
样例输出
4
5
6
package xuanze;
import java.util.*;
import java.util.*;
import java.io.*;
public class chapter4 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
String[] temp = reader.readLine().split(" ");
n = Integer.parseInt(temp[0]);
m = Integer.parseInt(temp[1]);
temp = reader.readLine().split(" ");
for (int i = 1; i <= n; ++i) {
a[i] = Integer.parseInt(temp[i - 1]);
e[i]=new ArrayList<>();
}
for (int i = 0; i < n - 1; ++i) {
temp = reader.readLine().split(" ");
int u = Integer.parseInt(temp[0]);
int v = Integer.parseInt(temp[1]);
e[u].add(v);
e[v].add(u);
}
dfs(1, 0);
for (int i = 1; i <= n; ++i) {
add(in[i], a[i]);
}
for (int i = 0; i < m; ++i) {
temp = reader.readLine().split(" ");
int op = Integer.parseInt(temp[0]);
int x = Integer.parseInt(temp[1]);
if (op == 1) {
int y = Integer.parseInt(temp[2]);
int v = rangeSum(in[x] - 1, in[x]);
add(in[x], y ^ v);
} else {
writer.write(rangeSum(in[x] - 1, out[x]) + "\n");
}
}
reader.close();
writer.flush();
writer.close();
}
static int N = 100010;
static int n, m, tot;
static int[] a = new int[N], in = new int[N], out = new int[N], b = new int[N];
static List<Integer>[] e = new List[N];
static void add(int x, int v) {
for (; x <= n; x += x & (-x)) {
b[x] ^= v;
}
}
static int sum(int x) {
int ans = 0;
if (x == 0) return 0;
for (; x > 0; x -= x & (-x)) {
ans ^= b[x];
}
return ans;
}
static int rangeSum(int l, int r) {
return sum(r) ^ sum(l);
}
static void dfs(int u, int fa) {
in[u] = ++tot;
for (int v : e[u]) {
if (v == fa) continue;
dfs(v, u);
}
out[u] = tot;
}
}
(注:此代码出于蓝桥云,非本人所写,宝宝么)