http://nanti.jisuanke.com/t/444
用的点分治,记录子节点到根节点的路径上的最小值和sum,按最小值从大到小排序,枚举右R端点,那么在1~R-1前面寻找与右端点不在同一颗子树内且sum值最大的点去更新答案.我们O(n)维护最大值和次大值
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 100005;
int n,T,son[N],f[N],root,sum,vis[N],k;
LL a[N],dis[N],ans;
struct Node{
LL mi,sum;int p;
bool operator<(const Node&cmp) const{
return mi>cmp.mi;
}
void output(){
cout<<mi<<" "<<sum<<" "<<p<<endl;
}
}node[N];int cnt;
struct Edge{
int to,next;
LL w;
}edge[N<<1];int head[N],tot;
void init(){
tot=0;
memset(vis,0,sizeof(vis));
memset(head,0xff,sizeof(head));
}
void addedge(int u,int v,LL w){
edge[tot].to=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
}
void getroot(int u,int pre){//寻找重心
son[u]=1;f[u]=0;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==pre||vis[v]) continue;
getroot(v,u);
son[u]+=son[v];
f[u]=max(f[u],son[v]);
}
f[u]=max(f[u],sum-son[u]);
if(f[u]<f[root]) root=u;
}
void dfs(int u,int pre,LL mi,int p){//点到根节点路径上的信息
mi=min(mi,a[u]);
node[cnt++]=(Node){mi,dis[u],p};
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==pre||vis[v]) continue;
dis[v]=dis[u]+edge[i].w;
dfs(v,u,mi,p);
}
}
void calc(int u){
cnt=dis[u]=k=0;
node[cnt++]=(Node){a[u],0,1};
for(int i=head[u];~i;i=edge[i].next){//划分路径
int v=edge[i].to;
if(vis[v]) continue;
k++;
dis[v]=edge[i].w;
dfs(v,u,min(a[u],a[v]),k);
}
sort(node,node+cnt);
// for(int i=0;i<cnt;++i){
// node[i].output();
// }
// cout<<endl;
LL mx1=0,mx2=0;int t1=0,t2=0;
for(int i=0;i<cnt;++i){//维护,更新
if(node[i].p!=t1)
ans=max(ans,node[i].mi*(node[i].sum+mx1));
else
ans=max(ans,node[i].mi*(node[i].sum+mx2));
if(node[i].sum>mx1){
if(node[i].p==t1){
mx1=node[i].sum;
}else{
mx2=mx1;t2=t1;
mx1=node[i].sum;t1=node[i].p;
}
}
else if(node[i].sum>mx2&&node[i].p!=t1){
mx2=node[i].sum;
t2=node[i].p;
}
}
}
void work(int u){
calc(u);
vis[u]=1;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(vis[v]) continue;
root=0;sum=son[v];
getroot(v,0);
// cout<<"root="<<root<<endl;
work(root);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init();
for(int i=1;i<=n;++i) scanf("%lld",a+i);
int u,v;LL w;
for(int i=0;i<n-1;++i){
scanf("%d%d%lld",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
ans=root=0;f[0]=inf;sum=n;
getroot(1,0);
// cout<<"root="<<root<<endl;
work(root);
printf("%lld\n",ans);
}
return 0;
}