题面
https://www.luogu.org/problem/AT3611
题解
点分,找到每个子树的拉格朗日点,然后把子树内所有的点向拉格朗日点连边。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<vector> #define N 200050 #define INF 1000000007LL #define ri register int using namespace std; int n,m,w[N]; int siz[N],vis[N]; int f[N]; vector<int> to[N],len[N]; struct edge{ int u,v; long long l; bool operator < (const edge &rhs) const { return l<rhs.l; } } e[N*50]; int findrt(int x) { if (f[x]==x) return x; return f[x]=findrt(f[x]); } void findroot(int x,int ff,int &rt,int &rts,int tot) { int curs=0; siz[x]=1; for (ri i=0,l=to[x].size();i<l;i++) if (to[x][i]!=ff && !vis[to[x][i]]) { findroot(to[x][i],x,rt,rts,tot); siz[x]+=siz[to[x][i]]; if (siz[to[x][i]]>curs) curs=siz[to[x][i]]; } if (tot-siz[x]>curs) curs=tot-siz[x]; if (curs<rts) rts=curs,rt=x; } void findP(int x,int ff,int &P,long long &pd,long long pred) { if (pred+w[x]<pd) pd=pred+w[x],P=x; for (ri i=0,l=to[x].size();i<l;i++) if (to[x][i]!=ff && !vis[to[x][i]]) { findP(to[x][i],x,P,pd,pred+len[x][i]); } } void link(int x,int ff,int P,long long pred) { e[++m]=(edge){x,P,pred+w[x]}; for (ri i=0,l=to[x].size();i<l;i++) if (to[x][i]!=ff && !vis[to[x][i]]) { link(to[x][i],x,P,pred+len[x][i]); } } void tonji(int x,int ff,int &tot){ tot++; for (ri i=0,l=to[x].size();i<l;i++) if (to[x][i]!=ff && !vis[to[x][i]]) tonji(to[x][i],x,tot); } void solve(int x){ vis[x]=1; int p=-1; long long pd=INF*INF; findP(x,-1,p,pd,0LL); link(x,-1,p,pd); for (ri i=0,l=to[x].size();i<l;i++) if (!vis[to[x][i]]) { int tot=0; tonji(to[x][i],x,tot); int rt=-1,rts=tot; findroot(to[x][i],x,rt,rts,tot); solve(rt); } } int main() { int a,b,c; scanf("%d",&n); for (ri i=1;i<=n;i++) scanf("%d",&w[i]); for (ri i=1;i<n;i++) { scanf("%d %d %d",&a,&b,&c); to[a].push_back(b); len[a].push_back(c); to[b].push_back(a); len[b].push_back(c); }; int rt=-1,rts=n; findroot(1,-1,rt,rts,n); solve(rt); sort(e+1,e+m+1); long long ans=0; for (ri i=1;i<=n;i++) f[i]=i; for (ri i=1;i<=m;i++) { int r1=findrt(e[i].u),r2=findrt(e[i].v); if (r1==r2) continue; ans+=e[i].l; f[r1]=r2; } cout<<ans<<endl; return 0; }