Bond

题目链接

Bond

给定一张 n 个点 m 条边的无向图,每条边有一个权值,有 q 个询问,每次询问给出两个点 (s,t),找到从一条从 st 的路径,使得最大权值最小,只需输出这个权值

解题思路

最小生成树,ST,树链剖分,并查集按秩合并,最小瓶颈生成树,kruskal重构树

首先,可以肯定一点,这条路径一定可以是最小生成树上的一条唯一路径
定理:最小生成树是最小瓶颈生成树,但是最小瓶颈生成树不一定是最小生成树

可利用 kruskal 算法求出最小生成树,再利用和 LCA 类似的思想求出最小生成树上两点之间的最大权值,或者求树上两点之间的最大值可利用树链剖分(树链剖分只是一种思想,可用线段树或 st 表来实现)来求,或者可以用 tarjan 离线求解,另外还可以kruskal重构树,答案即为重构树两点之间的 lca

当然,在利用并查集求最小生成树时可以按秩合并,这样整棵树的高度为 O(logn) 级别,这样只需要从 s 开始回溯并记录到该节点的最大值,然后从 t 开始回溯,如果遇到标记,该标记如果为根节点,说明两个点不在一条链上,则取记录到该节点的较大值;否则在一条链上仍取较大值,因为如果 t 位于 s 下面,遇到标记时说明 ts 的路径已经走过了,否则如果 t 位于 s 上面,则一开始就回溯,答案即为到 t 的最大值

由于边权是按从小到大排序的,每次合并时大的边权都集中在深度较低的位置,由于计算的是最大权值,即使向上回溯时有些边权没有统计到,但大的边权一定会统计到,所以不会对答案造成影响

  • 时间复杂度:O(mlogm+qlogn)

tarjan:

  • 时间复杂度:O(mlogm+q)

树链剖分(线段树):

  • 时间复杂度:O(mlogm+qlog2n)

树链剖分(st):

  • 时间复杂度:O(mlogm+qlogn)

kruskal 重构树:

  • 时间复杂度:O(mlogm+q)

代码

  • tarjan
// Problem: Bond // Contest: Virtual Judge - UVA // URL: https://vjudge.net/problem/UVA-11354 // Memory Limit: 1024 MB // Time Limit: 8000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5e4+5,M=1e5+5; int n,m,q,h[N],fa[N],up[N],res[M],w[N]; vector<PII> adj[N]; vector<PII> query[N]; PII ask[M]; vector<int> ids[N]; bool vis[N]; struct A { int x,y,w; bool operator<(const A &o) { return w<o.w; } }a[M]; void merge(int x,int y) { if(h[x]<h[y])fa[x]=y; else { fa[y]=x; if(h[x]==h[y])h[x]++; } } int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } int get(int x) { if(x==fa[x])return x; int t=get(fa[x]); up[x]=max(up[x],up[fa[x]]); return fa[x]=t; } void kruskal() { sort(a+1,a+1+m); int cnt=0; for(int i=1;i<=m;i++) { int x=a[i].x,y=a[i].y,w=a[i].w; int tx=x,ty=y; x=find(x),y=find(y); if(x==y)continue; cnt++; merge(x,y); adj[tx].emplace_back(ty,w); adj[ty].emplace_back(tx,w); if(cnt>=n-1)break; } } void add_query(int u,int v,int id) { query[u].emplace_back(v,id); query[v].emplace_back(u,id); } void tarjan(int u,int father) { up[u]=0; for(auto t:adj[u]) { int v=t.fi,w=t.se;; if(v==father)continue; tarjan(v,u); up[v]=w; fa[v]=u; } vis[u]=true; for(auto t:query[u]) { int v=t.fi,id=t.se; if(vis[v]) ids[get(v)].pb(id); } for(int id:ids[u]) { int u=ask[id].fi,v=ask[id].se; get(u),get(v); res[id]=max(up[u],up[v]); } } int main() { help; bool f=false; while(cin>>n>>m) { if(f)puts(""); f=true; for(int i=1;i<=n;i++) fa[i]=i,ids[i].clear(),adj[i].clear(),query[i].clear(),up[i]=vis[i]=h[i]=0; for(int i=1;i<=m;i++)cin>>a[i].x>>a[i].y>>a[i].w; kruskal(); for(int i=1;i<=n;i++)fa[i]=i; cin>>q; for(int i=1;i<=q;i++) { cin>>ask[i].fi>>ask[i].se; add_query(ask[i].fi,ask[i].se,i); } tarjan(1,0); for(int i=1;i<=q;i++) { cout<<res[i]<<'\n'; res[i]=0; } } return 0; }
  • ST+并查集路径压缩+按秩合并(高度)
// Problem: Bond // Contest: Virtual Judge - UVA // URL: https://vjudge.net/problem/UVA-11354 // Memory Limit: 1024 MB // Time Limit: 8000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5e4+5,M=1e5+5; int n,m,q,s,t,tt,fa[N],h[N],d[N],f[N][20],mx[N][20]; vector<PII> adj[N]; struct A { int a,b,w; bool operator<(const A &o) { return w<o.w; } }a[M]; int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } void merge(int x,int y) { if(h[x]<h[y]) fa[x]=y; else { fa[y]=x; if(h[x]==h[y])h[x]++; } } void kruskal() { int cnt=0; sort(a+1,a+1+m); for(int i=1;i<=m;i++) { int x=a[i].a,y=a[i].b,w=a[i].w; int tx=x,ty=y; x=find(x),y=find(y); if(x==y)continue; cnt++; merge(x,y); adj[tx].pb({ty,w}); adj[ty].pb({tx,w}); if(cnt>=n-1)break; } } void bfs() { queue<int> q; q.push(1); d[1]=1; while(q.size()) { int x=q.front(); q.pop(); for(auto t:adj[x]) { int y=t.fi,w=t.se; if(d[y])continue; d[y]=d[x]+1; f[y][0]=x; mx[y][0]=w; for(int i=1;i<=tt;i++)f[y][i]=f[f[y][i-1]][i-1],mx[y][i]=max(mx[y][i-1],mx[f[y][i-1]][i-1]); q.push(y); } } } int LCA(int x,int y) { if(d[x]<d[y])swap(x,y); int res=0; for(int i=tt;i>=0;i--) if(d[f[x][i]]>=d[y])res=max(res,mx[x][i]),x=f[x][i]; if(x==y)return res; for(int i=tt;i>=0;i--) if(f[x][i]&&f[x][i]!=f[y][i])res=max({res,mx[x][i],mx[y][i]}),x=f[x][i],y=f[y][i]; return max({res,mx[x][0],mx[y][0]}); } int main() { help; int T=0; while(cin>>n>>m) { for(int i=1;i<=n;i++)adj[i].clear(),h[i]=d[i]=0; if(T)puts(""); T++; tt=log(n)/log(2); for(int i=1;i<=m;i++)cin>>a[i].a>>a[i].b>>a[i].w; for(int i=1;i<=n;i++)fa[i]=i; kruskal(); bfs(); cin>>q; while(q--) { cin>>s>>t; cout<<LCA(s,t)<<'\n'; } } return 0; }
  • 树链剖分(线段树)
// Problem: Bond // Contest: Virtual Judge - UVA // URL: https://vjudge.net/problem/UVA-11354 // Memory Limit: 1024 MB // Time Limit: 8000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5e4+5,M=1e5+5; int n,m,x,y,d,q,s,t,fa[N],cnt,sz[N],son[N],pa[N],dep[N],top[N],nw[N],fw[N],id[N]; vector<PII> adj[N]; struct A { int x,y,w; bool operator<(const A &o) { return w<=o.w; } }a[M]; struct T { int l,r; int mx; }tr[4*N]; void pushup(int u) { tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx); } void build(int u,int l,int r) { tr[u]={l,r,0}; if(l==r) { tr[u].mx=nw[l]; return ; } int mid=l+r>>1; build(u<<1,l,mid),build(u<<1|1,mid+1,r); pushup(u); } int ask(int u,int l,int r) { if(l<=tr[u].l&&tr[u].r<=r)return tr[u].mx; int res=0; int mid=tr[u].l+tr[u].r>>1; if(l<=mid)res=max(res,ask(u<<1,l,r)); if(r>mid)res=max(res,ask(u<<1|1,l,r)); return res; } int ask_path(int u,int v) { int res=0; while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]])swap(u,v); res=max(res,ask(1,id[top[u]],id[u])); u=pa[top[u]]; } if(u==v)return res; if(dep[u]>dep[v])swap(u,v); res=max(res,ask(1,id[son[u]],id[v])); return res; } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void kruskal() { sort(a+1,a+1+m); for(int i=1;i<=m;i++) { int x=a[i].x,y=a[i].y,w=a[i].w; int tx=x,ty=y; x=find(x),y=find(y); if(x!=y) { fa[x]=y; adj[tx].pb({ty,w}),adj[ty].pb({tx,w}); } } } void dfs(int x,int fa,int depth) { sz[x]=1,pa[x]=fa,dep[x]=depth,son[x]=0; for(auto t:adj[x]) { int y=t.fi; if(y==fa)continue; fw[y]=t.se; dfs(y,x,depth+1); sz[x]+=sz[y]; if(sz[son[x]]<sz[y])son[x]=y; } } void dfs1(int x,int tt) { id[x]=++cnt,nw[cnt]=fw[x],top[x]=tt; if(!son[x])return ; dfs1(son[x],tt); for(auto t:adj[x]) { int y=t.fi; if(y==son[x]||y==pa[x])continue; dfs1(y,y); } } int main() { bool f=false; while(~scanf("%d%d",&n,&m)) { if(f)puts(""); f=true; for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w); for(int i=0;i<=n;i++)adj[i].clear(),fa[i]=pa[i]=i; kruskal(); cnt=-1; dfs(1,0,1); dfs1(1,1); build(1,0,cnt); cin>>q; while(q--) { scanf("%d%d",&s,&t); printf("%d\n",ask_path(s,t)); } } return 0; }
  • 树链剖分(st表)
// Problem: Bond // Contest: Virtual Judge - UVA // URL: https://vjudge.net/problem/UVA-11354 // Memory Limit: 1024 MB // Time Limit: 8000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5e4+5,M=1e5+5; int n,m,q,s,t,st[N][20],id[N],idx,sz[N],h[N],top[N],dep[N],son[N],fa[N],tt; vector<PII> adj[N]; int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } void merge(int x,int y) { if(h[x]<h[y]) fa[x]=y; else { fa[y]=x; if(h[x]==h[y])h[x]++; } } struct A { int x,y,w; bool operator<(const A&o) { return w<o.w; } }a[M]; void kruskal() { sort(a+1,a+1+m); int cnt=0; for(int i=1;i<=m;i++) { int x=a[i].x,y=a[i].y,w=a[i].w; int tx=x,ty=y; x=find(x),y=find(y); if(x==y)continue; cnt++; merge(x,y); adj[tx].emplace_back(ty,w); adj[ty].emplace_back(tx,w); if(cnt>=n-1)break; } } void dfs(int x) { sz[x]=1; son[x]=0; for(auto t:adj[x]) { int y=t.fi; if(y==fa[x])continue; dep[y]=dep[x]+1; fa[y]=x; dfs(y); sz[x]+=sz[y]; if(sz[son[x]]<sz[y])son[x]=y; } } void dfs(int x,int tt) { id[x]=++idx,top[x]=tt; if(son[x])dfs(son[x],tt); for(auto t:adj[x]) { int y=t.fi,w=t.se; if(y!=fa[x]&&y!=son[x]) dfs(y,y); if(y==fa[x])st[id[x]][0]=w; } } int ask_st(int l,int r) { int k=log(r-l+1)/log(2); return max(st[l][k],st[r-(1<<k)+1][k]); } int ask(int u,int v) { int res=0; while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]])swap(u,v); res=max(res,ask_st(id[top[u]],id[u])); u=fa[top[u]]; } if(u==v)return res; if(dep[u]>dep[v])swap(u,v); res=max(res,ask_st(id[son[u]],id[v])); return res; } int main() { help; bool f=false; while(cin>>n>>m) { if(f)puts(""); f=true; for(int i=1;i<=n;i++)adj[i].clear(),fa[i]=i; for(int i=1;i<=m;i++)cin>>a[i].x>>a[i].y>>a[i].w; tt=log(n)/log(2); kruskal(); fa[1]=0; dep[1]=1; dfs(1); idx=0; dfs(1,1); for(int j=1;j<=tt;j++) for(int i=1;i+(1<<j-1)<=n;i++) st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]); cin>>q; while(q--) { cin>>s>>t; cout<<ask(s,t)<<'\n'; } } return 0; }
  • 并查集按秩合并(大小)
// Problem: Bond // Contest: Virtual Judge - UVA // URL: https://vjudge.net/problem/UVA-11354 // Memory Limit: 1024 MB // Time Limit: 8000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=5e4+5,M=1e5+5; int n,m,x,y,d,q,s,t,fa[N],sz[N],e[N],vis[N]; struct A { int x,y,w; bool operator<(const A &o) { return w<=o.w; } }a[M]; int find(int x) { return fa[x]==x?x:find(fa[x]); } void merge(int x,int y,int w) { if(sz[x]<sz[y]) { fa[x]=y; sz[y]+=sz[x]; e[x]=w; } else { fa[y]=x; sz[x]+=sz[y]; e[y]=w; } } void kruskal() { sort(a+1,a+1+m); for(int i=1;i<=m;i++) { int x=a[i].x,y=a[i].y,w=a[i].w; x=find(x),y=find(y); if(x!=y)merge(x,y,w); } } void solve(int s,int t) { for(int i=0;i<=n;i++)vis[i]=0; int res1=1,res2=0; int now=s; while(true) { vis[now]=res1; if(now==fa[now])break; res1=e[now]; now=fa[now]; } now=t; while(true) { if(vis[now]) { res2=max(res2,vis[now]); break; } res2=e[now]; now=fa[now]; } cout<<res2<<'\n'; } int main() { help; bool f=false; while(cin>>n>>m) { if(f)puts(""); f=true; for(int i=1;i<=m;i++)cin>>a[i].x>>a[i].y>>a[i].w; for(int i=0;i<=n;i++)fa[i]=i,sz[i]=1; kruskal(); cin>>q; while(q--) { cin>>s>>t; solve(s,t); } } return 0; }
  • kruskal 重构树
// Problem: Bond // Contest: Virtual Judge - UVA // URL: https://vjudge.net/problem/UVA-11354 // Memory Limit: 1024 MB // Time Limit: 8000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N = 5e4 + 5, M = 1e5 + 5; int n, m; int w[N << 1], fa[N << 1], cnt, dfn[N << 2], pos[N << 1], time_stamp, d[N << 1]; int f[N << 2][20]; vector<int> adj[N << 1]; struct Tr { int l, r, w; bool operator<(const Tr &o)const { return w < o.w; } } tr[M]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } void kruskal() { sort(tr + 1, tr + 1 + m); for (int i = 1; i <= m; i++) { int x = tr[i].l, y = tr[i].r; x = find(x), y = find(y); if (x != y) { w[++cnt] = tr[i].w; adj[cnt].pb(x), adj[cnt].pb(y); fa[x] = cnt, fa[y] = cnt; } } } void dfs(int x, int fa) { dfn[++time_stamp] = x; pos[x] = time_stamp; d[x] = d[fa] + 1; for (int y : adj[x]) if (y != fa) { dfs(y, x); dfn[++time_stamp] = x; } } void init() { for (int i = 1; i <= time_stamp; i++) f[i][0] = dfn[i]; int t = __lg(time_stamp); for (int j = 1; j <= t; j++) for (int i = 1; i + (1 << j) - 1 <= time_stamp; i++) if (d[f[i][j - 1]] < d[f[i + (1 << j - 1)][j - 1]]) f[i][j] = f[i][j - 1]; else f[i][j] = f[i + (1 << j - 1)][j - 1]; } int ask(int x, int y) { int l = pos[x], r = pos[y]; if (l > r) swap(l, r); int t = __lg(r - l + 1); if (d[f[l][t]] < d[f[r - (1 << t) + 1][t]]) return w[f[l][t]]; return w[f[r - (1 << t) + 1][t]]; } int main() { help; bool f=false; while(cin>>n>>m) { if(f)puts(""); f=true; for(int i=1;i<=m;i++)cin>>tr[i].l>>tr[i].r>>tr[i].w; for(int i=0;i<=2*n;i++)fa[i]=i,adj[i].clear(); cnt=n; time_stamp=0; kruskal(); dfs(cnt, 0); init(); int q,s,t; for(cin>>q;q;q--) { cin>>s>>t; cout<<ask(s,t)<<'\n'; } } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16188383.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(99)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示