Cây là đồ thị liên thông không có chu trình với đỉnh và cạnh.
Khái niệm cơ bản
Cây có gốc (rooted tree) là cây trong đó một đỉnh được chọn làm gốc.
- Cha (parent): đỉnh liền kề gần gốc hơn
- Con (children): các đỉnh liền kề xa gốc hơn
- Lá (leaf): đỉnh không có con
- Độ sâu (depth): khoảng cách từ gốc,
- Chiều cao (height): độ sâu lớn nhất trong cây
- Cây con của (subtree): gồm và toàn bộ hậu duệ của
Duyệt cây (DFS)
const int MAXN = 2e5 + 5;
vector<int> adj[MAXN];
int par[MAXN], dep[MAXN];
void dfs(int u, int p) {
par[u] = p;
for (int v : adj[u])
if (v != p) {
dep[v] = dep[u] + 1;
dfs(v, u);
}
}
// dep[root] = 0; dfs(root, -1);
DFS in/out time (Euler Tour)
Gán thời điểm vào (tin) và ra (tout) cho mỗi đỉnh:
int tin[MAXN], tout[MAXN], order[MAXN], timer_dfs = 0;
void dfs(int u, int p) {
tin[u] = ++timer_dfs;
order[timer_dfs] = u;
for (int v : adj[u])
if (v != p) dfs(v, u);
tout[u] = timer_dfs;
}
- thuộc cây con của
tin[u] <= tin[v] && tout[v] <= tout[u] - Truy vấn/cập nhật toàn bộ cây con của = truy vấn đoạn
[tin[u], tout[u]]→ kết hợp với BIT/Segment Tree
Đường kính cây
Đường đi dài nhất giữa hai đỉnh bất kỳ. Tìm bằng hai lần BFS:
- BFS từ đỉnh bất kỳ → tìm đỉnh xa nhất
- BFS từ → tìm đỉnh xa nhất
- Đường kính =
pair<int,int> farthest(int src, int n) {
vector<int> dist(n+1, -1);
queue<int> q;
q.push(src); dist[src] = 0;
int far = src;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v : adj[u])
if (dist[v] == -1) {
dist[v] = dist[u] + 1;
q.push(v);
if (dist[v] > dist[far]) far = v;
}
}
return {far, dist[far]};
}
auto [u, d1] = farthest(1, n);
auto [v, diameter] = farthest(u, n);
Tổ tiên chung thấp nhất (LCA)
là tổ tiên chung gần nhất của và .
Binary Lifting — tiền xử lý, /truy vấn
Lưu = tổ tiên thứ của .
const int LOG = 18;
int up[MAXN][LOG], dep[MAXN];
void dfs(int u, int p) {
up[u][0] = p;
for (int i = 1; i < LOG; i++)
up[u][i] = up[up[u][i-1]][i-1];
for (int v : adj[u])
if (v != p) { dep[v] = dep[u] + 1; dfs(v, u); }
}
// up[root][0] = root; dep[root] = 0; dfs(root, root);
int lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
int diff = dep[u] - dep[v];
for (int i = 0; i < LOG; i++)
if ((diff >> i) & 1) u = up[u][i];
if (u == v) return u;
for (int i = LOG-1; i >= 0; i--)
if (up[u][i] != up[v][i]) { u = up[u][i]; v = up[v][i]; }
return up[u][0];
}
int dist(int u, int v) {
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
Các loại cây thường gặp
| Cấu trúc | Mục đích chính | Độ phức tạp |
|---|---|---|
| BST / AVL / Red-Black Tree | Tập hợp có thứ tự | |
| Treap | BST linh hoạt với split/merge | |
| Segment Tree | Truy vấn và cập nhật đoạn | |
| Fenwick Tree (BIT) | Prefix sum, cập nhật điểm | |
| Heap | Hàng đợi ưu tiên | |
| Trie | Lưu và tìm kiếm xâu/số |
Child pages
- Binary Lifting
- Cây nhị phân tìm kiếm (BST)
- Centroid Decomposition
- DSU on Tree (Small to Large)
- Fenwick Tree (Binary Indexed Tree)
- Heap / Hàng đợi ưu tiên
- Heavy-Light Decomposition (HLD)
- Li Chao Tree
- Link-Cut Tree
- Persistent Segment Tree
- Segment Tree (Cây phân đoạn)
- Segment Tree Beats
- Splay Tree
- Treap
- Trie (Cây tiền tố)
- Virtual Tree
Bình luận