题目让从一棵树上找到一个节点,使得其它所有节点到该节点的距离之和最短。若存在不只一个这样的节点,按照节点编号从小到大输出。
两次dfs就好了。
#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <set>
using namespace std;
typedef long long LL;
const int N = 50010;
int n, I, R;
LL ans;
int fst[N], nxt[N], to[N], e;
bool vis[N];
int cnt[N];//cnt为子树中的节点个数(包括自己)
LL sum[N];//表示i与其他所有节点距离的和
set<int>s;
void add(int u, int v) {
to[e] = v;
nxt[e] = fst[u];
fst[u] = e++;
}
void dfs(int u,LL d) {
vis[u] = true;
//dis[u] = d;
cnt[u] = 1;
sum[1] += d;
for (int i = fst[u]; i != -1; i = nxt[i]) {
int v = to[i];
if (!vis[v]) {
dfs(v, d + 1);
cnt[u] += cnt[v];
}
}
}
void DFS(int u) {
vis[u] = true;
ans = min(ans, sum[u]);
for (int i = fst[u]; i != -1; i = nxt[i]) {
int v = to[i];
if (!vis[v]) {
sum[v] = sum[u] + n - 2 * cnt[v];
DFS(v);
}
}
}
int main() {
//freopen("in.txt", "r", stdin);
int t; scanf("%d", &t);
while (t--) {
e = 0;
memset(fst, -1, sizeof fst);
scanf("%d %d %d", &n, &I, &R);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);
add(u, v);
add(v, u);
}
memset(vis, false, sizeof vis);
memset(sum, 0, sizeof sum);
dfs(1, 0LL);
memset(vis, false, sizeof vis);
ans = 0x3f3f3f3f;
DFS(1);
printf("%I64d\n", (LL)(ans*I*I*R));
int flag = 1;
for (int i = 1; i <= n; i++) {
if (ans == sum[i]) {
if (flag > 1)printf(" ");
flag++;
printf("%d", i);
}
}
printf("\n\n");
}
return 0;
}