ACMer分布在全国的n个不同的城市,编号为1~n。任意两个城市都连通,且只有唯一的一条通路。你们决定来一次全体聚会,请选出一个城市作为聚会地,使得所有人的距离和最小。
Input
第一行是一个整数T (1 ≤ T ≤ 10),表示样例的个数,所有测试数据样例总数不超过100。
每个样例的第一行是一个整数n (1 ≤ n ≤ 10000)。
第二行是n个整数,表示第i个城市里的ACMer的人数ai (1 ≤ ai ≤ 100)。
从第三行起的n - 1行,每行三个整数u, v, w, (1 ≤ u < v ≤ n), 1 ≤ w ≤ 100,表示城市u和v之间有一条路,距离为w。
Output
依次输出每个样例的结果,为两个整数,第一个为聚会城市的编号,第二个为所有人的距离和,两者之间用一个空格隔开。
如果存在多个符合条件的城市,取编号最小的。
Example
Input
Copy
1 6 1 2 3 4 5 6 1 2 1 1 3 1 2 4 1 2 5 1 3 6 1
Output
Copy
2 34
Note
选1号城市作为聚会地,距离和为(2 + 3)·1 + (4 + 5 + 6)·2 = 35。
选2号城市作为聚会地,距离和为(1 + 4 + 5)·1 + 3·2 + 6·3 = 34。
选3号城市作为聚会地,距离和为(1 + 7)·1 + 2·2 + (4 + 5)·3 = 39。
选4号城市作为聚会地,距离和为2·1 + (1 + 5)·2 + 3·3 + 6·4 = 47。
选5号城市作为聚会地,距离和为2·1 + (1 + 4)·2 + 3·3 + 6·4 = 45。
选6号城市作为聚会地,距离和为3·1 + 1·2 + 2·3 + (4 + 5)·4 = 47。
这是一道典型的换根DP,对于换根DP我们一般使用两次DFS,先任选一个节点作为根节点,树型DP搜索出每个子树的节点数(也就是人数),以及每个子树到根的代价,对于这题就是点与点的距离乘上人数。
第二次DFS进行换根,让孩子节点作为根与父节点为根的关系,对于本题,如果子节点变成根,那么子节点对应的子树上的人数到达根的代价都会减少 Wuv(边权),而父节点一边对应的代价便都会加大 Wuv;表达式就是:distv = distu - sumv*Wuv + (sum - sumv)*Wuv;最后遍历每个点找出最小代价。
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
//#define int long long
const long long INF = 0x3f3f3f3f3f3f;
struct node{
int to;
int nxt;
int w;
}e[20010];
long long cnt,ans = INF;
int head[10010],a[10010],dist[10010];
long long s = 0,sum[10010],f[10010];
void add(int u,int v,int w)
{
e[++cnt].nxt = head[u];
head[u] = cnt;
e[cnt].to = v;
e[cnt].w = w;
}
void dfs1(int u,int fa)
{
sum[u] = a[u];
for(int i = head[u];i;i = e[i].nxt)
{
int v = e[i].to;
if(v == fa)
{
continue;
}
dist[v] = dist[u] + e[i].w;//求出节点距离
dfs1(v,u);
sum[u] += sum[v];//预处理每个节点对应的子树的人数之和
}
}
void dfs2(int u,int fa)
{
for(int i = head[u];i;i = e[i].nxt)
{
int v = e[i].to;
if(v == fa) continue;
f[v] = f[u] - 1ll*sum[v]*e[i].w + 1ll*(s-sum[v])*e[i].w;//以v为根的代价和父节点为根的代价关系
dfs2(v,u);
}
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0);
int tt;
cin >> tt;
while(tt--)
{
s = 0;ans = INF;//注意初始化
int n;
cin >> n;
cnt = 0;
for(int i = 1;i <= n;i++)
{
dist[i] = 0;
f[i] = 0;
sum[i] = 0;
head[i] = 0;
cin >> a[i];
s += a[i];
}
for(int i = 1;i < n;i++)
{
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);add(b,a,c);
}
dfs1(1,1);
for(int i = 1;i <= n;i++)
{
f[1] += dist[i]*a[i];//以1为根的代价
}
dfs2(1,1);
int k = 0;
for(int i = 1;i <= n;i++)
{
if(f[i] < ans)
{
ans = f[i];
k = i;
}
}
cout << k << ' ' << ans << endl;
}
return 0;
}