bzoj1977 [BeiJing2010]次小生成树 Tree(kruskal+树上倍增)

来源:互联网 发布:sql注入攻击登录 编辑:程序博客网 时间:2024/06/05 15:50

先求出最小生成树,注意要严格次小。。。
枚举每一条非树边,把他加进来然后删掉这条非树边连接的两点在树上原来的路径上的最大边(保证是次小),(如果最大边与非树边边权相同则找次大边,为了严格次小)然后更新最小增量。
最大边和次大边可以通过树上倍增求出

#include <bits/stdc++.h>using namespace std;#define ll long long#define inf 0x3f3f3f3f#define N 100010#define M 300010inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}int n,m,fa[N][18],f[N],h[N],num=0,mx1[N][18],mx2[N][18],Log[N],dep[N];ll ans=0,res=inf;struct edge{    int x,y,val;bool f;}e[M];struct Edge{    int to,next,val;}data[N<<1];inline void add(int x,int y,int val){    data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;}inline bool cmp(edge x,edge y){    return x.val<y.val;}inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}void dfs(int x){    for(int i=1;i<=Log[n];++i){        if(!fa[x][i-1]) break;        fa[x][i]=fa[fa[x][i-1]][i-1];        mx1[x][i]=max(mx1[x][i-1],mx1[fa[x][i-1]][i-1]);        if(mx1[x][i-1]==mx1[fa[x][i-1]][i-1]) mx2[x][i]=max(mx2[x][i-1],mx2[fa[x][i-1]][i-1]);        else{            mx2[x][i]=min(mx1[x][i-1],mx1[fa[x][i-1]][i-1]);            mx2[x][i]=max(mx2[x][i],max(mx2[x][i-1],mx2[fa[x][i-1]][i-1]));        }    }    for(int i=h[x];i;i=data[i].next){        int y=data[i].to;if(y==fa[x][0]) continue;        fa[y][0]=x;dep[y]=dep[x]+1;mx1[y][0]=data[i].val;dfs(y);    }}int lca(int x,int y){    if(dep[x]<dep[y]) swap(x,y);    int d=dep[x]-dep[y];    for(int i=0;i<=Log[d];++i)        if(d&(1<<i)) x=fa[x][i];    if(x==y) return x;    for(int i=Log[n];i>=0;--i)        if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];    return fa[x][0];}void calc(int x,int y,int val){//找路径最大边和次大边     int d=dep[x]-dep[y],res1=0,res2=0;    for(int i=0;i<=Log[d];++i){        if(d&(1<<i)){            if(mx1[x][i]==res1) res2=max(res2,mx2[x][i]);            else if(mx1[x][i]>res1){                res2=res1;res1=mx1[x][i];                res2=max(res2,mx2[x][i]);            }else res2=max(res2,mx1[x][i]);        }    }    if(res1==val) res=min(res,(ll)val-res2);    else res=min(res,(ll)val-res1);}void solve(int x,int y,int val){    int t=lca(x,y);    calc(x,t,val);calc(y,t,val);}int main(){//  freopen("a.in","r",stdin);    n=read();m=read();    for(int i=1;i<=m;++i) e[i].x=read(),e[i].y=read(),e[i].val=read();    sort(e+1,e+m+1,cmp);Log[0]=-1;    for(int i=1;i<=n;++i) f[i]=i,Log[i]=Log[i>>1]+1;    for(int i=1;i<=m;++i){        int xx=find(e[i].x),yy=find(e[i].y);        if(xx!=yy){            f[xx]=yy;e[i].f=1;ans+=e[i].val;            add(e[i].x,e[i].y,e[i].val);add(e[i].y,e[i].x,e[i].val);        }    }dfs(1);    for(int i=1;i<=m;++i)//枚举非树边         if(!e[i].f) solve(e[i].x,e[i].y,e[i].val);    printf("%lld\n",ans+res);    return 0;}
阅读全文
0 0