什么是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 stubBufferedReader 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;}
}
(注:此代码出于蓝桥云,非本人所写,宝宝么)