[题解]P1967 [NOIP2013 提高组] 货车运输
题意简述
给定一个\(N\)个节点,\(M\)条边的无向图,其中每条边有一个边权。
接下来给定\(q\)次询问。每次询问给出\(x,y\),请计算\(x\)到\(y\)路径上最小边权的最大值是多少。
解题思路
我们对于每个连通块跑一遍最大生成树。这样整张图就成了一片森林。
接下来对于森林里的每一棵树,跑一遍LCA,顺便维护\(minn[pos][n]\)表示\(pos\)向上\(2^n\)层的最小边权。查询时,每跳一步更新最小边权,最终返回最小边权即可。
时间复杂度\(O(m\log m+q\log n)\)。
点击查看代码
#include<bits/stdc++.h> #define N 10010 #define M 50010 using namespace std; int n,m,q,ffa[N],dep[N],fa[N][20],minn[N][20]; //ffa用于并查集,fa用于LCA bool vis[N]; struct tedge{int u,v,w;}edges[M]; bool cmp(tedge a,tedge b){return a.w>b.w;} int find(int x){ if(ffa[x]==x) return x; return ffa[x]=find(ffa[x]); } struct edge{int to,w;}; vector<edge> G[N]; void dfs(int u,int father){ vis[u]=1; dep[u]=dep[father]+1; fa[u][0]=father; for(int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1], minn[u][i]=min(minn[u][i-1],minn[fa[u][i-1]][i-1]); for(auto i:G[u]) if(i.to!=father){ minn[i.to][0]=i.w; dfs(i.to,u); } } int lca(int u,int v){ if(dep[u]<dep[v]) swap(u,v); int ans=INT_MAX; for(int i=19;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) ans=min(ans,minn[u][i]), u=fa[u][i]; if(u==v) return ans; for(int i=19;i>=0;i--) if(fa[u][i]!=fa[v][i]) ans=min(ans,min(minn[u][i],minn[v][i])), u=fa[u][i],v=fa[v][i]; ans=min(ans,min(minn[u][0],minn[v][0])); return ans; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) ffa[i]=i; for(int i=1;i<=m;i++) cin>>edges[i].u>>edges[i].v>>edges[i].w; sort(edges+1,edges+1+m,cmp); for(int i=1;i<=m;i++){ int u=find(edges[i].u),v=find(edges[i].v); if(u==v) continue; ffa[u]=v; G[edges[i].u].push_back({edges[i].v,edges[i].w}); G[edges[i].v].push_back({edges[i].u,edges[i].w}); } for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0); cin>>q; while(q--){ int x,y; cin>>x>>y; if(find(x)!=find(y)) cout<<"-1\n"; else cout<<lca(x,y)<<"\n"; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效