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

  • 相关阅读:
    java_oop_方法2
    POJ 3276 Face The Right Way(反转)
    POJ 3276 Face The Right Way(反转)
    POJ 2566 Bound Found(尺取法,前缀和)
    POJ 2566 Bound Found(尺取法,前缀和)
    POJ 3320 Jessica's Reading Problem(尺取法)
    POJ 3320 Jessica's Reading Problem(尺取法)
    POJ 3061 Subsequence(尺取法)
    POJ 3061 Subsequence(尺取法)
    HDU 1222 Wolf and Rabbit(欧几里得)
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10674469.html
Copyright © 2011-2022 走看看