loj #136. 最小瓶颈路
#136. 最小瓶颈路
题目描述
给定一个包含 n nn 个节点和 m mm 条边的图,每条边有一个权值。
你的任务是回答 k kk 个询问,每个询问包含两个正整数 s ss 和 t tt 表示起点和终点,要求寻找从 s ss 到 t tt 的一条路径,使得路径上权值最大的一条边权值最小。
输入格式
第一行包含三个整数 n nn、m mm、k kk,分别表示 n nn 个节点, m mm 条路径, k kk 个询问。 接下来 m mm 行,每行三个整数 u uu , v vv , w ww, 表示一个由 u uu 到 v vv 的长度为 w ww 的双向边。 再接下来 k kk行,每行两个整数 s ss , t tt,表示询问从 s ss 连接到 t tt 的所有路径中单边长度最大值的最小值。
输出格式
输出包含 k kk 行,每一行包含一个整数 p pp 。p pp 表示 s ss 连接到 t tt 的所有路径中单边长度最大值的最小值。另外,如果 s ss 到 t tt 没有路径相连通,输出 -1
即可。
样例
样例输入
8 11 3
1 2 10
2 5 50
3 4 60
7 5 60
3 6 30
1 5 30
6 7 20
1 7 70
2 3 20
3 5 40
2 6 90
1 7
2 8
6 2
样例输出
30
-1
30
数据范围与提示
对于 30% 30\%30% 的数据 n≤100,m≤1000,k≤100,w≤1000 n \leq 100, m \leq 1000, k \leq 100, w \leq 1000n≤100,m≤1000,k≤100,w≤1000
对于 70% 70\%70% 的数据 n≤1000,m≤10000,k≤1000,w≤100000 n \leq 1000, m \leq 10000, k \leq 1000, w \leq 100000n≤1000,m≤10000,k≤1000,w≤100000
对于 100% 100\%100% 的数据 n≤1000,m≤100000,k≤1000,w≤10000000 n \leq 1000, m \leq 100000, k \leq 1000, w \leq 10000000n≤1000,m≤100000,k≤1000,w≤10000000
本题可能会有重边。
为了避免 Special Judge,本题所有的 w ww 均不相同。

#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 1010 using namespace std; int head[maxn],num,n,m,s,t,q,mx,mn=0x7fffffff; bool vis[maxn]; struct node{int to,pre,v;}e[200010]; void Insert(int from,int to,int v){ e[++num].to=to; e[num].v=v; e[num].pre=head[from]; head[from]=num; } bool check(int limit){ memset(vis,0,sizeof(vis)); queue<int>q; q.push(s);vis[s]=1; while(!q.empty()){ int now=q.front();q.pop(); for(int i=head[now];i;i=e[i].pre){ if(e[i].v>limit)continue; int to=e[i].to; if(!vis[to]){ if(to==t)return 1; vis[to]=1;q.push(to); } } } return vis[t]; } int qread(){ int i=0,j=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')j=-1;ch=getchar();} while(ch<='9'&&ch>='0'){i=i*10+ch-'0';ch=getchar();} return i*j; } int main(){ n=qread();m=qread();q=qread(); int x,y,z; for(int i=1;i<=m;i++){ x=qread();y=qread();z=qread(); Insert(x,y,z);Insert(y,x,z); mn=min(mn,z);mx=max(mx,z); } while(q--){ s=qread();t=qread(); int l=mn,r=mx,ans=-1; if(!check(mx)){puts("-1");continue;} if(s==t){puts("0");continue;} while(l<=r){ int mid=(l+r)>>1; if(check(mid))r=mid-1,ans=mid; else l=mid+1; } printf("%d\n",ans); } }

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 1010 using namespace std; int n,m,k,head[maxn],num,fa[maxn][21],dis[maxn][21],dep[maxn]; int f[maxn]; bool vis[maxn]; struct Node{ int u,v,w; bool operator < (const Node &b)const{ return w<b.w; } }E[100010]; struct node{int to,pre,v;}e[maxn*2]; void Insert(int from,int to,int v){ e[++num].to=to; e[num].v=v; e[num].pre=head[from]; head[from]=num; } int find(int x){ if(x==f[x])return x; return f[x]=find(f[x]); } void dfs(int x,int father){ fa[x][0]=father; dep[x]=dep[father]+1; vis[x]=1; for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(to==father)continue; dis[to][0]=e[i].v; dfs(to,x); } } int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y); int delta=dep[x]-dep[y]; int res=0; for(int i=0;i<=18;i++) if(delta&(1<<i)){ res=max(res,dis[x][i]); x=fa[x][i]; } for(int i=18;i>=0;i--) if(fa[x][i]!=fa[y][i]){ res=max(res,dis[x][i]); res=max(res,dis[y][i]); x=fa[x][i];y=fa[y][i]; } if(x==y)return res; res=max(res,dis[x][0]); res=max(res,dis[y][0]); return res; } int main(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=m;i++) scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w); sort(E+1,E+m+1); for(int i=1;i<=m;i++){ int f1=find(E[i].u),f2=find(E[i].v); if(f1!=f2){ f[f1]=f2; Insert(E[i].u,E[i].v,E[i].w); Insert(E[i].v,E[i].u,E[i].w); } } for(int i=1;i<=n;i++) if(!vis[i])dfs(i,0); for(int j=1;j<=20;j++) for(int i=1;i<=n;i++){ fa[i][j]=fa[fa[i][j-1]][j-1]; dis[i][j]=max(dis[i][j-1],dis[fa[i][j-1]][j-1]); } while(k--){ int s,t; scanf("%d%d",&s,&t); if(find(s)!=find(t)){ puts("-1"); continue; } printf("%d\n",lca(s,t)); } }