【NOIP2013】货车运输 最大生成树+倍增

时间:2022-12-16 23:43:20

题目大意:给你一张n个点m条边的图,有q次询问,每次让你找出一条从x至y的路径,使得路径上经过的边的最小值最大,输出这个最大的最小值。

显然,经过的路径必然在这张图的最大生成树上。

我们求出这个图的最大生成树后,用st表维护最小值,然后随便倍增下就好了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<vector>
 6 #include<algorithm>
 7 #include<set>
 8 #include<map>
 9 #include<queue>
10 #define M 100005
11 #define INF 19260817
12 using namespace std;
13 
14 int f[M][20]={0},minn[M][20]={0},dep[M]={0},vis[M]={0};
15 struct edge{int u,v,next;}e[M*2]={0}; int head[M]={0},use=0;
16 void dfs(int x,int fa,int v){
17     vis[x]=1; f[x][0]=fa; dep[x]=dep[fa]+1; minn[x][0]=v;
18     for(int i=1;i<20;i++) 
19     f[x][i]=f[f[x][i-1]][i-1],minn[x][i]=min(minn[x][i-1],minn[f[x][i-1]][i-1]);
20     for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa) dfs(e[i].u,x,e[i].v);
21 }
22 int getmin(int x,int y){
23     if(dep[x]<dep[y]) swap(x,y); int res=INF,cha=dep[x]-dep[y];
24     for(int i=19;~i;i--) if(cha&(1<<i)) res=min(res,minn[x][i]),x=f[x][i];
25     for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) res=min(res,min(minn[x][i],minn[y][i])),x=f[x][i],y=f[y][i];
26     if(x==y) return res; return min(res,min(minn[x][0],minn[y][0]));
27 }
28 
29 struct bian{
30     int x,y,z; bian(){x=y=z=0;}
31     friend bool operator <(bian a,bian b){return a.z<b.z;}
32 }a[M];
33 void add(int x,int y,int z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
34 int fa[M]={0};int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
35 
36 int main(){
37     memset(minn,1,sizeof(minn));
38     int n,m; scanf("%d%d",&n,&m);
39     for(int i=1;i<=n;i++) fa[i]=i;
40     for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
41     sort(a+1,a+m+1);
42     for(int i=m;i;i--){
43         int x=get(a[i].x),y=get(a[i].y);
44         if(x==y) continue;
45         add(a[i].x,a[i].y,a[i].z);
46         add(a[i].y,a[i].x,a[i].z);
47         fa[x]=y;
48     }
49     for(int i=1;i<=n;i++)
50     if(!vis[i]) dfs(i,0,INF);
51     int q; scanf("%d",&q);
52     while(q--){
53         int x,y; scanf("%d%d",&x,&y);
54         if(get(x)!=get(y)) printf("-1\n");
55         else printf("%d\n",getmin(x,y));
56     }
57 }