dfs序:
s[u]: dfs时进入u节点子树时的时间戳;
s[v]: dfs时离开u节点子树时的时间戳.
欧拉序:
E[i]: 第i时间访问到的节点
s[u]: dfs时进入u节点子树时的时间戳;
s[v]: dfs时离开u节点子树时的时间戳.
欧拉序:
E[i]: 第i时间访问到的节点
R[u]: 节点u被访问到的第一时间
Question:
给定树形图,然后q次询问,问点u是否是点v的父节点。
Answer:
通过dfs序判断v节点的时间区间是否在u节点的时间区间内。
通过欧拉序判断u和v的最近公共祖先是否是u。
Code1:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
vector<int> g[maxn];
int s[maxn], e[maxn];
int n, q, id;
void dfs(int u, int fa) {
s[u] = ++id;
for(int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if(v == fa) continue;
dfs(v, u);
}
e[u] = id;
}
int main() {
ios::sync_with_stdio(0);
cin >> n >> q;
for(int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
id = 0;
dfs(1, -1);
for(int i = 1; i <= q; ++i) {
int u, v;
cin >> u >> v;
if(s[u] <= s[v] && e[v] <= e[u]) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
}
}
return 0;
}
Code2:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
vector<int> g[maxn];
int E[maxn*2], R[maxn], dep[maxn];
int f[maxn*2][20];
int n, q, cnt;
void dfs(int u, int fa, int deps) {
E[++cnt] = u;
R[u] = cnt;
dep[u] = deps;
for(int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if(v == fa) continue;
dfs(v, u, deps+1);
E[++cnt] = u;
}
}
void rmq_init() {
for(int i = 1; i <= cnt; ++i) {
f[i][0] = E[i];
}
for(int j = 1; (1<<j) <= cnt; ++j) {
for(int i = 1; i+(1<<j)-1 <= cnt; ++i) {
int u = f[i][j-1], v = f[i+(1<<(j-1))][j-1];
f[i][j] = dep[u] < dep[v] ? u : v;
}
}
}
int rmq(int i, int j) {
int k = log2(j-i+1);
int u = f[i][k], v = f[j-(1<<k)+1][k];
return dep[u] < dep[v] ? u : v;
}
int lca(int u, int v) {
return rmq(min(R[u], R[v]), max(R[u], R[v]));
}
int main() {
ios::sync_with_stdio(0);
cin >> n >> q;
for(int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
cnt = 0;
dfs(1, -1, 1);
rmq_init();
for(int i = 1; i <= q; ++i) {
int u, v;
cin >> u >> v;
if(lca(u, v) == u) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
}
}
return 0;
}
加油~