zoukankan      html  css  js  c++  java
  • AtCoder3611 Tree MST

    题目描述

    题解

    不可能把完全图的边都找出来,需要考虑能否删去一些边使其与完全图的 $ ext{mst}$ 相同。

    有 $ ext{dis}$ 我们可以考虑点分治,即对于一个点分中心,如果有三个点 $x,y,z$ ,如果 $W(x,y) le W(y,z)$ 并且 $W(x,z) le W(y,z)$ ,那我们在做 $ ext{mst}$ 的时候肯定不会加上 $W(y,z)$ 这一条边。

    所以我们可以找到 $W(x,rt)$ 最小的 $x$ ,然后每个点都和 $x$ 相连,这样得到的图的 $ ext{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;
    }
  • 相关阅读:
    VC编程规范
    socket编程FTP客户端demo
    Win7下微软拼音等中文输入法默认英文标点解决办法
    <转载>一般筛法和快速线性筛法求素数
    聚类算法的设计与实现
    面试题集锦_7
    面试题集锦_8
    中点画线算法程序
    HTML解析类 ,让你不使用正则也能轻松获取HTML相关元素 C# .NET
    .NET C# 使用S22.Imap.dll接收邮件 并且指定收取的文件夹的未读邮件,并且更改未读准态
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12437034.html
Copyright © 2011-2022 走看看