https://nanti.jisuanke.com/t/32235
This is Yet Another Tree Problem. You are given a tree, where every node has a penalty and every edge has a weight. The cost of a simple path between any two nodes is the sum of the weights of the edges in the path, plus the product of the penalties of the endpoint nodes. Note that a path can have 0 edges, and the cost of such a path is simply the square of the penalty of the node.
For each node, compute the smallest cost of any path starting at that node. The final answer is the sum of all of these minimum costs.
Input
Each input will consist of a single test case. Note that your program may be run multiple times on different inputs. The first line of input will consist of a single integer
n
(
1
≤
n
≤
200
,
000
)
n (1 \le n \le 200,000)
n(1≤n≤200,000), which is the number of nodes. The next line will consist of n space-separated integers
p
(
1
≤
p
≤
1
,
000
,
000
)
p (1 \le p \le 1,000,000)
p(1≤p≤1,000,000), which is the penalty of each node, in order. Each of the following n - 1 lines will consist of three space-separated integers i, j and w
(
1
≤
i
≤
n
,
1
≤
j
≤
n
,
i
≠
j
,
1
≤
w
≤
1
,
000
,
000
)
(1 \le i \le n,1 \le j \le n,i \ne j,1 \le w \le 1,000,000)
(1≤i≤n,1≤j≤n,i̸=j,1≤w≤1,000,000), specifying an edge between nodes i and j with weight w.
Output
Output a single integer, which is the sum of all of the lowest cost paths for each node.
样例输入
5
9 7 1 1 9
3 2 8
5 2 10
4 3 10
2 1 2
样例输出
63
思路:点分治+斜率优化
#include<bits/stdc++.h>
using namespace std;
const int MOD=1e6+3;
const int MAX=2e5+10;
typedef long long ll;
vector<pair<int,int> >e[MAX];
int v[MAX];
int son[MAX],siz[MAX];
int sum,root;
void getsum(int k,int fa)
{
sum++;
for(int i=0;i<e[k].size();i++)
{
pair<int,int>nex=e[k][i];
if(nex.first==fa||v[nex.first])continue;
getsum(nex.first,k);
}
}
void getroot(int k,int fa)
{
son[k]=0;
siz[k]=1;
for(int i=0;i<e[k].size();i++)
{
pair<int,int>nex=e[k][i];
if(nex.first==fa||v[nex.first])continue;
getroot(nex.first,k);
siz[k]+=siz[nex.first];
son[k]=max(son[k],siz[nex.first]);
}
son[k]=max(son[k],sum-son[k]);
if(son[k]<son[root])root=k;
}
struct lenka{ll ax,dx;}A[MAX],B[MAX];
int cmp(const lenka&a,const lenka&b)
{
if(a.ax==b.ax)return a.dx<b.dx;
return a.ax<b.ax;
}
int cnt,p[MAX];
ll a[MAX],d[MAX];
void getdeep(int k,int fa)
{
A[++cnt]=(lenka){a[k],d[k]};
p[cnt]=k;
for(int i=0;i<e[k].size();i++)
{
pair<int,int>nex=e[k][i];
if(nex.first==fa||v[nex.first])continue;
d[nex.first]=d[k]+nex.second;
getdeep(nex.first,k);
}
}
ll ans[MAX];
ll check(int x,int y){return B[x].dx+d[y]+B[x].ax*a[y];}
void cal(int k,int fa)
{
cnt=0;
d[k]=0;
getdeep(k,0);
sort(A+1,A+cnt+1,cmp);
int top=1;
B[top]=A[1];
for(int i=2;i<=cnt;i++)
{
while(top>1&&(A[i].dx-B[top].dx)*(A[i].ax-B[top-1].ax)<=(A[i].dx-B[top-1].dx)*(A[i].ax-B[top].ax))top--;
B[++top]=A[i];
}
for(int i=1;i<=cnt;i++)
{
int L=1,R=top;
while(R-L>1)
{
int mid=(L+R)/2;
int mm=(mid+R)/2;
if(check(mid,p[i])>check(mm,p[i]))L=mid;
else R=mm;
}
ans[p[i]]=min(ans[p[i]],check(L,p[i]));
ans[p[i]]=min(ans[p[i]],check(R,p[i]));
}
}
void solve(int k)
{
cal(k,0);
v[k]=1;
for(int i=0;i<e[k].size();i++)
{
pair<int,int>nex=e[k][i];
if(v[nex.first])continue;
sum=0;
getsum(nex.first,0);
root=0;
son[root]=sum+1;
getroot(nex.first,0);
solve(root);
}
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)ans[i]=a[i]*a[i];
for(int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
e[x].push_back({y,z});
e[y].push_back({x,z});
}
sum=n;
root=0;
son[root]=sum+1;
getroot(1,0);
solve(root);
ll tot=0;
for(int i=1;i<=n;i++)tot+=ans[i];
cout<<tot<<endl;
return 0;
}