题解 CF1675F Vlad and Unfinished Business
Description
Vlad 和 Nastya 住在一个有着
Vlad 住在
求 Vlad 最少要用多久才能办完所有事并来到 Nastya 家。
Solution
我们以 Vlad 家为根节点,那么我们最后再去 Nastya 家所在的子树。因为如果先去了 Nastya 家那边,还得再回 Vlad 家去别的地方办事,这样就浪费了时间,因为最后还得去 Nastya 家。
因此我们每下到一个结点,就判断这个结点一下是否还有事情要办,如果有事就下去办,如果 Nastya 在那个子树就最后再去。
Code
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
int to[200005], fa[200005];
bool task[200005];
vector<int> tr[200005];
bool dfs1(int x) {//建立树结构
for (int i = 0; i < tr[x].size(); i++) {
int &go = tr[x][i];
if (go == fa[x])
continue;
fa[go] = x;
task[x] |= dfs1(go);
}
return task[x];
}
bool dfs2(int x, int y) {//找到 Nastya 家
if (x == y)
return 1;
for (int i = 0; i < tr[x].size(); i++) {
int &go = tr[x][i];
if (go == fa[x])
continue;
if (dfs2(go, y)) {
to[x] = go;
return 1;
}
}
return 0;
}
int dfs3(int x) {//正式行动
int ans = 0;
for (int i = 0; i < tr[x].size(); i++) {
int &go = tr[x][i];
if (go == fa[x])
continue;
if (to[x] != go && task[go])
ans += dfs3(go) + 2;
}
if (to[x] != -1)
ans += dfs3(to[x]) + 2;
return ans;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
memset(task, 0, sizeof(task));
memset(to, -1, sizeof(to));
memset(fa, -1, sizeof(fa));
int n, k, x, y;
scanf("%d%d%d%d", &n, &k, &x, &y);
for (int i = 1; i <= k; i++) {
int a;
scanf("%d", &a);
task[a] = 1;
}
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
tr[u].emplace_back(v);
tr[v].emplace_back(u);
}
dfs1(x);
dfs2(x, y);
int ans = dfs3(x), now = x;
while (now != y) {//因为 dfs3 最后会回到根节点,因此要减去两人家之间的距离
now = to[now];
ans--;
}
printf("%d\n", ans);
for (int i = 1; i <= n; i++)
tr[i].clear();
}
return 0;
}