CF29D Ant on the Tree
目录
题目
CF29D Ant on the Tree
算法标签: d f s dfs dfs, 树上差分
思路
由于点的数量很少 300 300 300, 因此时间复杂度在 O ( n 3 ) O(n ^ 3) O(n3)之内都可以通过, 考虑 d f s dfs dfs, 从叶子结点开始搜, 因为 d f s dfs dfs记录顺序是逆序, 因此倒着搜就是正序, 时间复杂度 O ( n 2 ) O(n ^ 2) O(n2)
d f s dfs dfs代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N = 310;
vector<int> head[N], ans;
void add(int u, int v) {
head[u].push_back(v);
}
bool dfs(int u, int fa, int t) {
if (u == t) return true;
for (int v : head[u]) {
if (v != fa && dfs(v, u, t)) {
ans.push_back(v);
return true;
}
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
add(u, v), add(v, u);
}
int t = 1, s;
while (cin >> s) dfs(s, 0, t), t = s;
dfs(1, 0, t);
ans.push_back(1);
if (ans.size() != 2 * n - 1) {
cout << -1 << "\n";
return 0;
}
for (int x : ans) cout << x << " ";
cout << "\n";
return 0;
}
树上差分代码
在差分过程中, 计算每个节点应该经过的次数, 然后在统计的时候就能计算出每个节点应该被经过多少次, 从而判断是否是合法的
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N = 310, M = 10;
int n;
int fa[N][M], depth[N];
int diff[N], order[N], cnt;
vector<int> head[N];
void add(int u, int v) {
head[u].push_back(v);
}
void dfs(int u, int pre, int dep) {
fa[u][0] = pre, depth[u] = dep;
int is_leaf = 1;
for (int v : head[u]) {
if (v == pre) continue;
dfs(v, u, dep + 1);
is_leaf = 0;
}
cnt += is_leaf;
}
int lca(int u, int v) {
if (depth[u] < depth[v]) swap(u, v);
for (int i = M - 1; i >= 0; --i) {
if (depth[fa[u][i]] >= depth[v]) u = fa[u][i];
}
if (u == v) return u;
for (int i = M - 1; i >= 0; --i) {
if (fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
void check(int u, int pre) {
for (int v : head[u]) {
if (v == pre) continue;
check(v, u);
diff[u] += diff[v];
}
if (u > 1 && diff[u] != 2) {
cout << -1 << "\n";
exit(0);
}
}
void move(int u, int v) {
int rev = 0;
if (depth[u] < depth[v]) {
swap(u, v);
rev = 1;
}
vector<int> ans;
while (u != v) {
ans.push_back(rev ? u : fa[u][0]);
u = fa[u][0];
}
if (rev) reverse(ans.begin(), ans.end());
for (int u : ans) cout << u << " ";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
add(u, v), add(v, u);
}
dfs(1, 0, 1);
// 处理倍增数组
for (int i = 1; i < M; ++i) {
for (int u = 1; u <= n; ++u) {
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
}
// 起点终点都是1
order[0] = order[cnt + 1] = 1;
// 处理差分数组
for (int i = 1; i <= cnt; ++i) {
if (i <= cnt) cin >> order[i], diff[order[i]] += 2;
int p = lca(order[i - 1], order[i]);
diff[p] -= 2;
}
check(1, 0);
cout << "1 ";
for (int i = 1; i <= cnt + 1; ++i) {
int p = lca(order[i - 1], order[i]);
move(order[i - 1], p);
move(p, order[i]);
}
cout << "\n";
return 0;
}