严格次小生成树
题目大意:
给定一个无向图,求出该图的次小生成树。
点数n≤100 000 边数m≤300 000
做法其实是比较简单的,首先我们求出给定图中的最小生成树,然后我们枚举每一条非树边,将其加入生成树中,可以证明这样一定会出现一个环,我们只需要在这个环中找到除去这条边以外最大的边,(又因为是严格次小生成树,所以还有找次小的,以防最大值与非树边边权相等),将它删去,然后得到另一个生成树,记录一下ans,对于所有非树边枚举得到的ans只要取一个最小值就可以了(因为是次小生成树)
但是这种做法的复杂度有点大,我们来分析一下:求最小生成树是O(n),(由于并查集时间复杂度可以看作是一个常数),枚举非选择的边是O(m),每一次求最大值(和次大值)也是O(m),所以渐近时间复杂度是O(m^2),如果要通过这道题还是差了很多。
那么我们进行优化:
很显然最小生成树不能优化,每一条非树边都必须被枚举,所以我们只能在求最大值上下手了。
考虑到我们在加入该非树边之前应该是一颗没有环的树,那么求一段路径上的最大值我们是会做的,树链剖分?代码量过于大了,那么我们考虑另一种做法:树上倍增LCA
其实LCA可以干很多事情的。。。
关于LCA求树上两点路径中边权最大值,这个其实是比较简单的,我们在原来的基础上开一个w[u][i],表示从u向上跳2^i个点,这一段路径的最大值
动态转移方程也是比较显然的:我们假定f[u][i]表示从u向上跳2^i个点到达点的坐标,那么就有w[u][i+1]=max(w[u][i],w[f[u][i]][i])
所以我们只需要就从这两个点分别跳到他们的LCA处,每一次取最大值就可以了,这样我们就将m^2的算法转化成了mlogn,这样通过这道题就轻松加愉快了
但是我们忽略了一点:
题目中要求严格次小,但是这种做法很有可能就是和最小生成树相等,那么我们还需要解决这个难题。
其实也不算是难题,只是在原来的基础上多记录一个次大值,我们假设w2[u][i]表示从u向上跳2^i个单位,这段路径上的次大值。
动态转移方程就是:当w[u][i]>w[f[u][i]][i] w2[u][i+1]=max(w[f[u][i]][i],w2[f[u][i]][i])
当w[u][i]<w[f[u][i]][i] w2[u][i+1]=max(w[u][i],w2[f[u][i]][i])
当相等时,就继承上一个段的就可以了
那么我们就圆满的解决了这道题,总复杂度:mlogn+n*k k为一个比较小的常数
还有一些注意事项:
1.inf要足够大 因为这个边权之和很大很大
2.建树时要建反向边,谁知道给定的两个点相对顺序呢?
最后,附上本题代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 using namespace std; 5 //Debug Yufenglin 6 #define dej printf("Running\n"); 7 #define dep1(x) cout<<#x<<"="<<x<<endl; 8 #define dep2(x,y) cout<<#x<<"="<<x<<' '<<#y<<"="<<y<<endl; 9 #define dep3(x,y,z) cout<<#x<<"="<<x<<' '<<#y<<"="<<y<<' '<<#z<<"="<<z<<endl; 10 11 //Standfor Yufenglin 12 #define LL long long 13 #define LB long double 14 #define reg register 15 #define il inline 16 #define inf 1e8 17 #define maxn 100000 18 #define maxm 300000 19 20 struct EDGE 21 { 22 LL u,v,w; 23 }; 24 struct TREE 25 { 26 LL to,val,nxt; 27 }; 28 TREE tree[maxm+5]; 29 EDGE edge[maxm+5]; 30 LL n,m; 31 LL fa[maxn+5],f[maxn+5][30],w1[maxn+5][30],maxw1,maxw2,cnt,num; 32 LL head[maxn+5],dep[maxn+5],w2[maxn+5][30],ans,minans=1e16,sum; 33 bool vis[maxm+5]; 34 35 bool cmp(EDGE x,EDGE y) 36 { 37 return x.w<y.w; 38 } 39 void add(LL x,LL y,LL z) 40 { 41 edge[++cnt].u=x; 42 edge[cnt].v=y; 43 edge[cnt].w=z; 44 } 45 void addedge(LL x,LL y,LL z) 46 { 47 tree[++num].to=y; 48 tree[num].val=z; 49 tree[num].nxt=head[x]; 50 head[x]=num; 51 } 52 LL find(LL x) 53 { 54 if(fa[x]==x) return x; 55 return fa[x]=find(fa[x]); 56 } 57 void dfs(LL u,LL fa) 58 { 59 dep[u]=dep[fa]+1; 60 f[u][0]=fa; 61 for(int i=0; i<=25; i++) 62 { 63 f[u][i+1]=f[f[u][i]][i]; 64 w1[u][i+1]=max(w1[u][i],w1[f[u][i]][i]); 65 w2[u][i+1]=max(w2[u][i],w2[f[u][i]][i]); 66 if(w1[u][i]>w1[f[u][i]][i]) w2[u][i+1]=max(w2[u][i+1],w1[f[u][i]][i]); 67 if(w1[u][i]<w1[f[u][i]][i]) w2[u][i+1]=max(w2[u][i+1],w1[u][i]); 68 } 69 for(int i=head[u]; i; i=tree[i].nxt) 70 { 71 if(tree[i].to==fa) continue; 72 w1[tree[i].to][0]=tree[i].val; 73 dfs(tree[i].to,u); 74 } 75 } 76 LL LCA(LL x,LL y) 77 { 78 if(dep[x]<dep[y]) swap(x,y); 79 for(int i=25; i>=0; i--) 80 { 81 if(dep[f[x][i]]>=dep[y]) 82 { 83 x=f[x][i]; 84 } 85 if(x==y) return x; 86 } 87 for(int i=25; i>=0; i--) 88 { 89 if(f[x][i]!=f[y][i]) 90 { 91 x=f[x][i]; 92 y=f[y][i]; 93 } 94 } 95 return f[x][0]; 96 } 97 LL query(LL x,LL y,LL d) 98 { 99 LL anst=-1; 100 for(int i=25;i>=0;i--) 101 { 102 if(dep[f[x][i]]>=dep[y]) 103 { 104 if(d!=w1[x][i]) anst=max(anst,w1[x][i]); 105 else anst=max(anst,w2[x][i]); 106 x=f[x][i]; 107 } 108 } 109 return anst; 110 } 111 int main() 112 { 113 scanf("%lld%lld",&n,&m); 114 for(int i=1; i<=m; i++) 115 { 116 LL x,y,z; 117 scanf("%lld%lld%lld",&x,&y,&z); 118 add(x,y,z); 119 } 120 sort(edge+1,edge+cnt+1,cmp); 121 for(int i=1; i<=n; i++) fa[i]=i; 122 for(int i=1; i<=m; i++) 123 { 124 if(find(edge[i].u)!=find(edge[i].v)) 125 { 126 addedge(edge[i].u,edge[i].v,edge[i].w); 127 addedge(edge[i].v,edge[i].u,edge[i].w); 128 fa[find(edge[i].u)]=find(edge[i].v); 129 ans+=edge[i].w; 130 vis[i]=1; 131 sum++; 132 } 133 if(sum==n-1) break; 134 } 135 for(int i=1;i<=n;i++) w2[i][0]=-1; 136 dfs(1,0); 137 for(int i=1; i<=m; i++) 138 { 139 if(vis[i]==0) 140 { 141 LL lca=LCA(edge[i].u,edge[i].v); 142 LL maxu=query(edge[i].u,lca,edge[i].w); 143 LL maxv=query(edge[i].v,lca,edge[i].w); 144 minans=min(minans,ans-max(maxu,maxv)+edge[i].w); 145 } 146 } 147 printf("%lld\n",minans); 148 return 0; 149 }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步