BZOJ 1977 次小生成树(最近公共祖先)
Posted GFY
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1977 次小生成树(最近公共祖先)相关的知识,希望对你有一定的参考价值。
题意:求一棵树的严格次小生成树,即权值严格大于最小生成树且权值最小的生成树。
先求最小生成树,对于每个不在树中的边,取两点间路径的信息,如果这条边的权值等于路径中的权值最大值,那就删掉路径中的次大值,加上这条非树边,更新答案;否则删掉路径中的最大值,加上这条非树边,更新答案。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #define ll long long 7 struct edge{ 8 int u,v,id; 9 ll w; 10 }e[300005]; 11 int tot,go[600005],first[300005],next[600005]; 12 ll val[600005]; 13 int fa[100005][18],deep[100005],F[100005],bin[105],n,m; 14 ll mx1[100005][18],mx2[100005][18],ans1,ans2; 15 int read(){ 16 char ch=getchar();int t=0,f=1; 17 while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();} 18 while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();} 19 return t*f; 20 } 21 ll Read(){ 22 char ch=getchar();ll t=0,f=1; 23 while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();} 24 while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();} 25 return t*f; 26 } 27 bool cmp(edge a,edge b){ 28 return a.w<b.w; 29 } 30 void insert(int x,int y,ll z){ 31 tot++; 32 go[tot]=y; 33 next[tot]=first[x]; 34 first[x]=tot; 35 val[tot]=z; 36 } 37 void add(int x,int y,int z){ 38 insert(x,y,z);insert(y,x,z); 39 } 40 int find(int x){ 41 if (F[x]==x) return x; 42 else return (find(F[x])); 43 } 44 void up(ll x,ll &y){ 45 if (x>y) y=x; 46 } 47 void work(int x,int i){ 48 mx1[x][i]=std::max(mx1[fa[x][i-1]][i-1],mx1[x][i-1]); 49 if (mx1[fa[x][i-1]][i-1]<mx1[x][i]) up(mx1[fa[x][i-1]][i-1],mx2[x][i]); 50 if (mx1[x][i-1]<mx1[x][i]) up(mx1[x][i-1],mx2[x][i]); 51 up(mx2[x][i-1],mx2[x][i]); 52 up(mx2[fa[x][i-1]][i-1],mx2[x][i]); 53 } 54 void dfs(int x,int f){ 55 for (int i=1;i<=17;i++) 56 fa[x][i]=fa[fa[x][i-1]][i-1],work(x,i); 57 for (int i=first[x];i;i=next[i]){ 58 int pur=go[i]; 59 if (pur==f) continue; 60 deep[pur]=deep[x]+1; 61 fa[pur][0]=x; 62 mx1[pur][0]=val[i]; 63 mx2[pur][0]=0; 64 dfs(pur,x); 65 } 66 } 67 void up(ll x,ll &a,ll &b){ 68 if (x>a) b=a,a=x; 69 else 70 if (x>b&&x<a) b=x; 71 } 72 void lca(int x,int y){ 73 ans1=0,ans2=0; 74 if (deep[x]<deep[y]) std::swap(x,y); 75 int t=deep[x]-deep[y]; 76 for (int i=0;i<=17;i++) 77 if (t&bin[i]) { 78 up(mx1[x][i],ans1,ans2); 79 up(mx2[x][i],ans1,ans2); 80 x=fa[x][i]; 81 } 82 for (int i=17;i>=0;i--) 83 if (fa[x][i]!=fa[y][i]) { 84 up(mx1[x][i],ans1,ans2); 85 up(mx2[x][i],ans1,ans2); 86 up(mx1[y][i],ans1,ans2); 87 up(mx2[y][i],ans1,ans2); 88 x=fa[x][i]; 89 y=fa[y][i]; 90 } 91 if (x!=y){ 92 up(mx1[x][0],ans1,ans2); 93 up(mx2[x][0],ans1,ans2); 94 up(mx1[y][0],ans1,ans2); 95 up(mx2[y][0],ans1,ans2); 96 } 97 } 98 int main(){ 99 bin[0]=1; 100 for (int i=1;i<=17;i++) bin[i]=bin[i-1]*2; 101 n=read();m=read(); 102 for (int i=1;i<=m;i++){ 103 e[i].u=read(); 104 e[i].v=read(); 105 e[i].w=Read(); 106 e[i].id=0; 107 } 108 for (int i=1;i<=n;i++) 109 for (int j=0;j<=17;j++) 110 mx1[i][j]=mx2[i][j]=0; 111 std::sort(e+1,e+1+m,cmp); 112 ll sum=0; 113 for (int i=1;i<=n;i++) F[i]=i; 114 for (int i=1;i<=m;i++) 115 if (find(e[i].u)!=find(e[i].v)){ 116 F[find(e[i].u)]=find(e[i].v); 117 e[i].id=1; 118 add(e[i].u,e[i].v,e[i].w); 119 sum+=e[i].w; 120 } 121 dfs(1,0); 122 ll Ans=10000000000000000LL; 123 for (int i=1;i<=m;i++) 124 if (!e[i].id){ 125 lca(e[i].u,e[i].v); 126 if (e[i].w==ans1) Ans=std::min(Ans,sum-ans2+e[i].w); 127 else Ans=std::min(Ans,sum-ans1+e[i].w); 128 } 129 printf("%lld\n",Ans); 130 }
以上是关于BZOJ 1977 次小生成树(最近公共祖先)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1977 [BeiJing2010组队]次小生成树 Tree
刷题总结——次小生成树(bzoj1977 最小生成树+倍增)
严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)
bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树