基礎樹論
Basics
Sparse Table
Binary Indexed Tree
Segment Tree
簡報自己讀不懂很正常他偏抽象
基本概念
存圖&遍歷
int n;
vector<vector<int>> adj(n + 1);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u); // 無向邊要建雙向
}
void dfs(int u, int p) {
// process node u
for (int v : adj[u]) {
if (v == p) continue; // 防止往回走
dfs(v, u);
}
}
// main
dfs(root, -1); // 通常根節點是 1 可以直接 dfs(1, -1);
auto dfs = [&](auto self, int u, int p) -> void {
// process node u
for (int v : adj[u]) {
if (v == p) continue;
self(self, v, u);
}
}; // 記得加分號
// main
dfs(dfs, root, -1);
vector<int> dist(n + 1, -1);
queue<int> q;
dist[start] = 0;
q.push(start);
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);
}
}
}
子樹大小
題目
void dfs(int u, int p) {
cnt[u] = 1;
for (int v : adj[u]) {
if (v == p) continue;
dfs(v, u); // 要先處理完子節點再更新狀態
cnt[u] += cnt[v];
}
}
樹直徑
題目
int s = 1, dia = 0;
vector<int> depth(n + 1);
auto dfs = [&](auto self, int u, int p) -> void {
if (depth[u] > dia) {
dia = depth[u];
s = u;
}
for (int v : adj[u]) if (v != p) {
depth[v] = depth[u] + 1;
self(self, v, u);
}
};
dfs(dfs, 1, -1);
depth[s] = 0;
dfs(dfs, s, -1);
auto dfs = [&](auto self, int u, int p) -> int {
int mx = 0, mx2 = 0;
for (int v : adj[u]) if (v != p) {
int h = self(self, v, u) + 1;
if (h > mx) {
mx2 = mx;
mx = h;
} else if (h > mx2) {
mx2 = h;
}
}
dia = max(dia, mx + mx2);
return mx;
};
dfs(dfs, 1, -1);
全源最長路
題目
auto dfs = [&](auto self, int u, int p) -> void {
for (int v : adj[u]) if (v != p) {
self(self, v, u);
if (maxDist[v] + 1 > maxDist[u]) {
secMax[u] = maxDist[u];
maxDist[u] = maxDist[v] + 1;
path[u] = v;
} else if (maxDist[v] + 1 > secMax[u]) {
secMax[u] = maxDist[v] + 1;
}
}
};
auto dfs2 = [&](auto self, int u, int p) -> void {
for (int v : adj[u]) if (v != p) {
if (path[u] == v) { // maxDist[u] is the path toward v
if (secMax[u] + 1 > maxDist[v]) {
secMax[v] = maxDist[v];
maxDist[v] = secMax[u] + 1;
path[v] = u;
} else if (secMax[u] + 1 > secMax[v]) {
secMax[v] = secMax[u] + 1;
}
} else { // maxDist[u] + 1 >= maxDist[v] in this case
// cause if not, then maxDist[u] should calculated as maxDist[v] + 1 in first dfs
secMax[v] = maxDist[v];
maxDist[v] = maxDist[u] + 1;
path[v] = u;
}
self(self, v, u);
}
};
換根 DP
題目
auto dfs = [&](auto self, int u, int p, int dist) -> void {
ans[1] += dist;
sz[u] = 1; // 計算子樹大小
for (int v : adj[u]) if (v != p) {
self(self, v, u, dist + 1);
sz[u] += sz[v];
}
};
auto dfs2 = [&](auto self, int u, int p) -> void {
for (int v : adj[u]) if (v != p) {
ans[v] = ans[u] - sz[v] + (n - sz[v]);
self(self, v, u);
}
};
倍增法
題目
vector<vector<int>> succ(__lg(n) + 1, vector<int>(n + 1));
vector<int> depth(n + 1);
auto dfs = [&](auto self, int u) -> void {
for (int v : adj[u]) {
succ[0][v] = u;
depth[v] = depth[u] + 1;
for (int i = 1; i <= __lg(depth[v]); i++) {
succ[i][v] = succ[i - 1][succ[i - 1][v]];
}
self(self, v);
}
};
for (int i = lg(k); i >= 0; i--) {
if (k & (1 << i)) {
x = succ[i][x];
}
}
最低共通祖先
題目
auto lca = [&](int x, int y) -> int {
if (depth[x] < depth[y]) swap(x, y);
while (depth[x] > depth[y]) {
x = succ[lg(depth[x] - depth[y])][x];
}
if (x == y) return x; // 如果定位到同深度時已經找到 要先返回
for (int i = lg(depth[x]); i >= 0; i--) {
if (succ[i][x] != succ[i][y]) {
x = succ[i][x], y = succ[i][y];
}
}
return succ[0][x];
};
vector<int> timer(2 * n + 1), id(n + 1), depth(n + 1);
auto dfs = [&](auto self, int u) -> void {
id[u] = cnt;
timer[cnt++] = u;
for (int v : adj[u]) {
depth[v] = depth[u] + 1;
self(self, v);
timer[cnt++] = u;
}
};
vector<vector<int>> st(lg(cnt) + 1, vector<int>(cnt + 1));
for (int i = 1; i <= cnt; i++) st[0][i] = i;
for (int i = 1; i <= lg(cnt); i++) {
int len = 1 << (i - 1);
for (int j = 1; j + len <= cnt; j++) {
int a = st[i - 1][j], b = st[i - 1][j + len];
if (depth[timer[a]] <= depth[timer[b]]) st[i][j] = a;
else st[i][j] = b;
}
}
int l = id[a], r = id[b];
if (l > r) swap(l, r);
int k = lg(r - l + 1);
a = st[k][l], b = st[k][r - (1 << k) + 1];
if (depth[timer[a]] <= depth[timer[b]]) {
cout << timer[a] << '\n';
} else cout << timer[b] << '\n';
樹壓平
題目
auto dfs = [&](auto self, int u, int p) -> void {
st[u] = ++cnt;
for (int v : adj[u]) if (v != p) {
self(self, v, u);
}
en[u] = cnt;
};
BIT tree(n);
for (int i = 1; i <= n; i++) {
tree.modify(st[i], v[i]);
}
if (o == 1) { // modify
int x;
cin >> x;
tree.modify(st[s], x);
} else {
cout << tree.query(en[s]) - tree.query(st[s] - 1) << '\n';
}