AtCoder3611 Tree MST
题解
不可能把完全图的边都找出来,需要考虑能否删去一些边使其与完全图的 $\text{mst}$ 相同。
有 $\text{dis}$ 我们可以考虑点分治,即对于一个点分中心,如果有三个点 $x,y,z$ ,如果 $W(x,y) \le W(y,z)$ 并且 $W(x,z) \le W(y,z)$ ,那我们在做 $\text{mst}$ 的时候肯定不会加上 $W(y,z)$ 这一条边。
所以我们可以找到 $W(x,rt)$ 最小的 $x$ ,然后每个点都和 $x$ 相连,这样得到的图的 $\text{mst}$ 是等效于原来的完全图的,而这张图的边数是 $O(nlogn)$ 的,所以总效率为 $O(nlog^2n)$ 。
代码
#include <bits/stdc++.h> #define I inline #define LL long long using namespace std; const int N=2e5+5;bool vis[N];LL G,s; int n,m,X,f[N],sz[N],son[N],rt,o,hd[N],V[N*2],a[N],W[N*2],nx[N*2],t; struct O{int u,v;LL w;}p[N*50]; int get(int x){return x==f[x]?x:f[x]=get(f[x]);} I void add(int u,int v,int w){ nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w; } #define v V[i] I void getrt(int x,int fa){ sz[x]=1;son[x]=0; for (int i=hd[x];i;i=nx[i]) if (v!=fa && !vis[v]) getrt(v,x),sz[x]+=sz[v], son[x]=max(son[x],sz[v]); son[x]=max(o-sz[x],son[x]); if (son[x]<son[rt]) rt=x; } I void find(int u,int fa,LL w){ if (w+a[u]<G) G=w+a[u],X=u; for (int i=hd[u];i;i=nx[i]) if (!vis[v] && v!=fa) find(v,u,w+W[i]); } I void ins(int u,int fa,LL w){ p[++m]=(O){u,X,G+w+a[u]}; for (int i=hd[u];i;i=nx[i]) if (!vis[v] && v!=fa) ins(v,u,w+W[i]); } I void work(int x){ vis[x]=1;G=2e18;X=0; find(x,0,0ll);ins(x,0,0ll); for (int i=hd[x];i;i=nx[i]) if (!vis[v]) rt=0,o=sz[v], getrt(v,x),work(rt); } #undef v bool cmp(O A,O B){return A.w<B.w;} int main(){ son[0]=1e9; scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=i; for (int x,y,z,i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z), add(x,y,z),add(y,x,z); t=0;o=n;getrt(1,0);work(rt); sort(p+1,p+m+1,cmp); for (int u,v,i=1;i<=m;i++){ u=get(p[i].u);v=get(p[i].v); if (u!=v) s+=p[i].w;f[u]=v; } cout<<s<<endl;return 0; }