zoukankan      html  css  js  c++  java
  • BZOJ 1977: [BeiJing2010组队]次小生成树 Tree 倍增 最小生成树

    好吧我太菜了又调了一晚上。。。QAQ


    先跑出最小生成树,标记树边,再用树上倍增的思路,预处理出:

      f[u][i] :距离u为2^i的祖先

      h[u][i][0/1] :距u点在2^i范围内的最长边和次长边

    然后枚举每一条非树边(u,v),会与原先的最小生成树构成一个环,而之前预处理出的数据可以快速找到(u,v)在最小生成树上的最大和次大边,来更新答案

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define int long long
    #define R register int
    using namespace std;
    inline int g() {
        R ret=0,fix=1;register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    struct node{int u,v,w;bool operator <(const node & y) const { return w<y.w;}}a[600010];
    struct edge{int v,w,nxt;}e[200010];
    int n,m,cnt,mx,mmx,mn=0x3f3f3f3f,ans,tot; 
    int fir[100010],f[100010][20],h[100010][20][2],fa[100010],d[100010];
    bool tr[600010];
    inline void add(int u,int v,int w) {e[++cnt].v=v,e[cnt].nxt=fir[u],e[cnt].w=w,fir[u]=cnt;}
    inline void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
    inline int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
    inline void dfs(int u,int fa) {
        for(R i=fir[u];i;i=e[i].nxt) {
            R v=e[i].v; if(v==fa) continue;
            f[v][0]=u,h[v][0][0]=e[i].w,d[v]=d[u]+1;
            for(R i=1;d[v]>=(1<<i);++i) {
                f[v][i]=f[f[v][i-1]][i-1]; 
                h[v][i][0]=max(h[v][i-1][0],h[f[v][i-1]][i-1][0]);
                if(h[v][i-1][0]==h[f[v][i-1]][i-1][0]) 
                    h[v][i][1]=max(h[v][i-1][1],h[f[v][i-1]][i-1][1]);
                else {
                    h[v][i][1]=min(h[v][i-1][0],h[f[v][i-1]][i-1][0]);
                    h[v][i][1]=max(h[v][i-1][1],h[v][i][1]);
                    h[v][i][1]=max(h[v][i][1],h[f[v][i-1]][i-1][1]);
                }
            } dfs(v,u);
        }
    }
    inline int lca(int u,int v) {
        if(d[u]<d[v]) swap(u,v); R lim=log2(d[u])+1; 
        for(R j=lim;j>=0;--j) if(d[f[u][j]]>=d[v]) u=f[u][j];
        if(u==v) return u; 
        for(R j=lim;j>=0;--j) if(f[u][j]!=f[v][j]) u=f[u][j],v=f[v][j];
        return f[u][0];
    }
    inline void calc(int u,int fa,int w) {
        mx=0,mmx=0; R lim=log2(d[u]-d[fa])+1;
        for(R i=lim;i>=0;--i) if(d[u]-d[fa]>=(1<<i)){
            if(h[u][i][1]>mx) mmx=mx,mx=h[u][i][0];
            mx=max(h[u][i][0],mx); mmx=max(mmx,h[u][i][1]),u=f[u][i];
        }
        if(mx!=w) mn=min(mn,w-mx); else mn=min(mn,w-mmx);
    }
    signed main() {
        n=g(),m=g();
        for(R i=1;i<=n;++i) fa[i]=i;
        for(R i=1;i<=m;++i) a[i].u=g(),a[i].v=g(),a[i].w=g();
        sort(a+1,a+m+1);
        for(R i=1;i<=m&&tot<n;++i) {
            R uf=getf(a[i].u),vf=getf(a[i].v);
            if(uf==vf) continue;
            fa[uf]=vf; ans+=a[i].w; tr[i]=true;
            ins(a[i].u,a[i].v,a[i].w); ++tot;
        } dfs(1,0);
        for(R i=1;i<=m;++i) if(!tr[i]) {
            R L=lca(a[i].u,a[i].v);
            calc(a[i].u,L,a[i].w); calc(a[i].v,L,a[i].w);
        } printf("%lld
    ",ans+mn);
    }

    2019.04.09

  • 相关阅读:
    控制器的功能和工作原理
    数据通路的功能和基本结构
    指令的执行过程
    CPU的功能和基本组成结构
    CSS介绍
    html内容
    web简单介绍
    事务隔离机制介绍
    多版本并发控制MVCC
    数据库锁机制
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10674469.html
Copyright © 2011-2022 走看看