【NOIP2013】货车运输 最大生成树+倍增
题目大意:给你一张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 }