作为一个电子商务为主体的公司,京东一直努力实现自己“多、快、好、省”的承诺。其中,“快”的特质更是被京东发挥到了极致。京东建立了一个非常高效的物流网络,物流网络构成了一个树结构,由很多的物流点和将物流点连结起来的道路组成。
京东物流网络中每个物流点有一个权值 di,物流点间的道路也都有一个权值 wi。对于一条物流网络中的路径,令路径上所有物流点权值 di 的最小值为 mind,路径上所有道路权值 wi 的总和为 sumw,则该条路径的总权值为 mind * sumw。路径的起点和终点可以是物流网络中的任意物流点,且路径中不能出现重复的物流点。
请求出京东的这个树形物流网络所有路径总权值中的最大值。
输入格式
第一行输入一个整数 T(1 ≤ T ≤ 50),表示数据组数。
每组数据第一行一个整数 n(1 ≤ n ≤ 105),表示有 n 个物流点。
之后一行 n 个整数,表示每个物流点的权重 di(1 ≤ di ≤ 109)。
接下来有 n - 1 行,每行 3 个整数 ui,vi,wi(1 ≤ ui, vi ≤ n, 1 ≤ wi ≤ 109),表示有一条连接 ui 和 vi 的权值为 wi 的道路。输入数据保证没有重复出现的(ui,vi)点对,且最终一定会形成一个树形物流网络。
最多有 10 组数据的 n 超过 104。
输出格式
一共输出 T 行,每行一个整数,表示路径总权值的最大值。
样例1
输入:
1 3 1 2 3 1 2 1 1 3 2
输出:
3
提示信息
总权值最大的路径是 2 - 1 - 3,mind 为 min(1, 2, 3) = 1,sumw 为 sum(1, 2) = 3,因此总权值为 1 * 3 = 3。
第一步:深度优先遍历整棵树,对于子树选择子树的重心作为子树的root节点继续递归
第二步:深度优先遍历每个子树,考虑所有的分支节点到root节点之间的路径长度sumw和路径最小点权mind和相对于root的子树分支编号id,用stk[]数组保存三个变量。
第三步:将stk[]数组中按mind从大到小排序,依次考虑每一条终点为root节点的路径,合并id编号不同的两条路径(root即为中间节点),保留考虑过的路径中路径长度最长的路径path1,和与path1路径不同id号的次长路径path2(这样不至于两个最长路径(id号相同)合并时出现路径重合情况,解决方案是和path2合并路径)
注:第三步做法的依据是先从mind大号枚举路径考虑到mind较小节点时,我们最想和此路径(mind较小点所在路径)和并的路径是之前考虑过的路径中路径最长的路径。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 210000
#define LL long long
#define inf 0x0f0f0f0f
struct Node{
int nxt,val;
Node(){}
Node(int _n,int _v){ nxt = _n; val = _v; }
};
struct STK{
int id,wei;
LL len;
STK(){}
STK(int _id,int _w,LL _l){
id = _id; wei = _w; len = _l;
}
};
STK stk[N];
vector<Node> nod[N];
int size[N],vis[N],f[N],wgt[N];
int root,top;
LL ans;
LL max(LL a,LL b){ return a>b?a:b; }
LL min(LL a,LL b){ return a<b?a:b; }
int Cmp(STK k1,STK k2){ return k1.wei > k2.wei; }
void getRoot(int cur,int fa,int sum){
int tmp = 0;
size[cur] = 1;
for(int i = 0;i<(int)nod[cur].size();i++){
int nxt = nod[cur][i].nxt;
if(vis[nxt]||nxt==fa) continue;
getRoot(nxt,cur,sum);
size[cur] += size[nxt];
tmp = max(tmp,size[nxt]);
}
f[cur] = max(tmp,sum - size[cur]);
if(f[root]>f[cur]) root = cur;
}
void dfs(int cur,int fa,LL len,int wei,int id){
stk[++top] = STK(id,wei,len);
for(int i = 0;i<(int)nod[cur].size();i++){
int nxt = nod[cur][i].nxt;
int val = nod[cur][i].val;
if(vis[nxt]||nxt==fa) continue;
dfs(nxt,cur,len+val,min(wei,wgt[nxt]),id);
}
}
void CDQ(int cur,int sum){
root = 0; f[root] = inf;
getRoot(cur,-1,sum);
int tmp_r = root;
vis[tmp_r] = 1;
//printf("====%d,%d\n",cur,tmp_r);
for(int i = 0;i<(int)nod[tmp_r].size();i++){
int nxt = nod[tmp_r][i].nxt;
if(vis[nxt]) continue;
CDQ(nxt,size[nxt]);
}
int id = 0;
top = 0;
for(int i = 0;i<(int)nod[tmp_r].size();i++){
int nxt = nod[tmp_r][i].nxt;
if(vis[nxt]) continue;
int val = nod[tmp_r][i].val;
dfs(nxt,tmp_r,val,min(wgt[nxt],wgt[tmp_r]),++id);
}
sort(stk+1,stk+top+1,Cmp);
STK pri1 = STK(0,inf,0),pri2 = STK(-1,inf,0);
for(int i = 1;i<=top;i++){
if(pri1.id!=stk[i].id)
ans = max(ans,(LL)stk[i].wei*(stk[i].len + pri1.len));
else
ans = max(ans,(LL)stk[i].wei*(stk[i].len + pri2.len));
if(pri1.len < stk[i].len){
if(pri1.id==stk[i].id)
pri1 = stk[i];
else{
pri2 = pri1;
pri1 = stk[i];
}
}
else if((pri2.len<stk[i].len)&&(stk[i].id!=pri1.id)){
pri2 = stk[i];//没有考虑到WA了n多发
}
}
vis[tmp_r] = 0;
}
void init(){
for(int i = 0;i<N;i++) nod[i].clear();
memset(vis,0,sizeof(vis));
}
int main(){
int T,a,b,n,v;
//freopen("Test.txt","r",stdin);
scanf("%d",&T);
while(T--){
init();
scanf("%d",&n);
for(int i = 1;i<=n;i++)
scanf("%d",&wgt[i]);
for(int i = 1;i<n;i++){
scanf("%d%d%d",&a,&b,&v);
nod[a].push_back(Node(b,v));
nod[b].push_back(Node(a,v));
}
ans = 0;
CDQ(1,n);
printf("%lld\n",ans);
}
return 0;
}