标签:
和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护答案即可。
代码
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N = 201010; 5 const int M = 1000100; 6 const int inf = 2000000000; 7 int f[N],n,m,i; 8 int dp,p[N],pre[M],tt[M],ww[M],flag[M]; 9 int deep[N],jump[N][18],mi[N][18],Mi[N][18]; 10 long long ans,Ans; 11 struct g{ 12 int l,r,v; 13 }a[M]; 14 void link(int x,int y,int z) 15 { 16 dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;ww[dp]=z; 17 } 18 bool cmp(g a,g b) 19 { 20 return a.v<b.v; 21 } 22 int gf(int x) 23 { 24 while (x!=f[x]) x=f[x];return x; 25 } 26 void dfs(int x,int fa,int va) 27 { 28 deep[x]=deep[fa]+1; 29 jump[x][0]=fa; 30 mi[x][0]=va; 31 Mi[x][0]=-inf; 32 int i; 33 for (i=1;i<=17;i++) 34 { 35 jump[x][i]=jump[jump[x][i-1]][i-1]; 36 mi[x][i]=max(mi[x][i-1],mi[jump[x][i-1]][i-1]); 37 if (mi[x][i-1]==mi[jump[x][i-1]][i-1]) 38 Mi[x][i]=max(Mi[x][i-1],Mi[jump[x][i-1]][i-1]); 39 else 40 if (mi[x][i-1]<mi[jump[x][i-1]][i-1]) 41 Mi[x][i]=max(mi[x][i-1],Mi[jump[x][i-1]][i-1]); 42 else 43 Mi[x][i]=max(Mi[x][i-1],mi[jump[x][i-1]][i-1]); 44 } 45 i=p[x]; 46 while (i) 47 { 48 if (tt[i]!=fa) 49 dfs(tt[i],x,ww[i]); 50 i=pre[i]; 51 } 52 } 53 void updata(int x,int y,int &ans,int &Ans) 54 { 55 if (x>=ans) 56 { 57 if (x>ans) 58 Ans=max(Ans,ans); 59 Ans=max(Ans,y); 60 ans=x; 61 } 62 else 63 if (x>Ans) 64 Ans=max(Ans,x); 65 } 66 int get(int a,int b,int c) 67 { 68 if (deep[a]<deep[b]) a^=b^=a^=b; 69 int i,ans=-inf,Ans=-inf; 70 for (i=17;i>=0;i--) 71 if (deep[jump[a][i]]>=deep[b]) 72 { 73 updata(mi[a][i],Mi[a][i],ans,Ans); 74 a=jump[a][i]; 75 } 76 if (a==b) 77 { 78 if (ans==c) return Ans;else return ans; 79 } 80 for (i=17;i>=0;i--) 81 if (jump[a][i]!=jump[b][i]) 82 { 83 updata(mi[a][i],Mi[a][i],ans,Ans); 84 updata(mi[b][i],Mi[b][i],ans,Ans); 85 a=jump[a][i];b=jump[b][i]; 86 } 87 updata(mi[a][0],Mi[a][0],ans,Ans); 88 updata(mi[b][0],Mi[b][0],ans,Ans); 89 if (ans==c) return Ans;else return ans; 90 } 91 int main() 92 { 93 scanf("%d%d",&n,&m); 94 for (i=1;i<=m;i++) 95 scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].v); 96 sort(a+1,a+1+m,cmp); 97 for (i=1;i<=n;i++) f[i]=i; 98 for (i=1;i<=m;i++) 99 { 100 int l=a[i].l,r=a[i].r; 101 if (gf(l)!=gf(r)) 102 { 103 link(l,r,a[i].v); 104 link(r,l,a[i].v); 105 f[gf(l)]=gf(r); 106 Ans+=a[i].v; 107 flag[i]=1; 108 } 109 } 110 dfs(1,0,0); 111 ans=(long long) inf*inf; 112 for (i=1;i<=m;i++) 113 if (!flag[i]) 114 { 115 long long tmp=Ans-get(a[i].l,a[i].r,a[i].v)+a[i].v; 116 if ((tmp>Ans)&&(tmp<ans)) ans=tmp; 117 } 118 printf("%lld\n",ans); 119 }
bzoj1977 [BeiJing2010组队]次小生成树 Tree
标签:
原文地址:http://www.cnblogs.com/fzmh/p/5510055.html