MST(最小生成树+倍增)
题目描述:
给定一个n个点m条边的连通图,保证没有自环和重边。对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成树上。假如最大权值为无限大,则输出-1。
题解:
先求出图的一棵最小生成树:
对于不在树上的边(x,y), 它的权值只要小于树上x到y路径中一条边就可以代替这条边。
对于在树上的边(x,y),可以先预处理出所有两端在x到y路径上的不在树上的边的最小值。它的权值一定要小于最小值。
路径max和min都可以用倍增求。
时间复杂度O(nlogn)
#include<bits/stdc++.h> using namespace std; const int N=2e5+5; inline int read(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,cnt=0,head[N]; int vis[N],ans[N]; int fa[N],dep[N],id[N]; int f[N][20],maxn[N][20]; struct data{ int x,y,dis,id; }a[N]; struct Edge{ int v,w,nxt,id; }edge[N<<1]; void add_edge(int u,int v,int w,int id){ edge[++cnt].v=v;edge[cnt].w=w;edge[cnt].id=id;edge[cnt].nxt=head[u];head[u]=cnt; } int find(int x){ if(fa[x]==x) return fa[x]; else return fa[x]=find(fa[x]); } bool cmp(data a,data b){ return a.dis<b.dis; } void build(){ sort(a+1,a+m+1,cmp); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++){ int x=a[i].x; int y=a[i].y; if(find(x)!=find(y)){ fa[find(x)]=find(y); vis[a[i].id]=1; add_edge(x,y,a[i].dis,a[i].id); add_edge(y,x,a[i].dis,a[i].id); } } } void dfs(int u){ for(int i=1;i<=18;i++){ f[u][i]=f[f[u][i-1]][i-1]; maxn[u][i]=max(maxn[u][i-1],maxn[f[u][i-1]][i-1]); } for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].v; int w=edge[i].w; if(v==f[u][0]) continue; dep[v]=dep[u]+1; id[v]=edge[i].id; f[v][0]=u; maxn[v][0]=w; dfs(v); } } void solve(int x,int y,int dis){ x=find(x); while(dep[x]>dep[y]){ ans[id[x]]=min(ans[id[x]],dis-1); int k=find(f[x][0]); fa[x]=k; x=find(x); } } int get(int x,int y,int &lca){ int ans=0; if(dep[x]<dep[y]) swap(x,y); for(int i=18;i>=0;i--) if(dep[f[x][i]]>=dep[y]){ ans=max(ans,maxn[x][i]); x=f[x][i]; } if(x==y){ lca=x; return ans; } for(int i=18;i>=0;i--){ if(f[x][i]!=f[y][i]){ ans=max(ans,maxn[x][i]); ans=max(ans,maxn[y][i]); x=f[x][i],y=f[y][i]; } } lca=f[x][0]; return max(ans,max(maxn[x][0],maxn[y][0])); } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){ a[i].x=read();a[i].y=read();a[i].dis=read(); ans[i]=2e9; a[i].id=i; } build();dfs(1); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++){ if(!vis[a[i].id]){ int x=a[i].x,y=a[i].y,z; ans[a[i].id]=get(x,y,z)-1; solve(x,z,a[i].dis); solve(y,z,a[i].dis); } } for(int i=1;i<=m;i++){ if(ans[i]==2e9) printf("-1 "); else printf("%d ",ans[i]); } }