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;
}

 

posted @ 2020-03-07 20:58  xjqxjq  阅读(171)  评论(0编辑  收藏  举报