NOIP2013货车运输
题目描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入
第一行有两个用一个空格隔开的整数n,m,表示A国有n座城市和m条道路。接下来m行每行3个整数x、y、z,每两个整数之间用一个空格隔开,表示从x号城市到y号城市有一条限重为z的道路。注意:x不等于y,两座城市之间可能有多条道路。接下来一行有一个整数q,表示有q辆货车需要运货。接下来q行,每行两个整数x、y,之间用一个空格隔开,表示一辆货车需要从x城市运输货物到y城市,注意:x不等于y。
数据范围:n最大10000,m最大50000,q为30000,z为100000.
输出
共有q行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
样例输入
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
样例输出
3
-1
3
做法
两点之间尽可能大的最小承重路径一定在最大生成树上,于是问题转化为查询最大生成树上,两点之间的最小边的查询,可以倍增,也可以树剖。注意还有可能不能互相到达。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
const int N = 10010;
const int M = 50100;
const int inf = 0x3f3f3f3f;
inline int read() {char c=getchar(); int x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
using namespace std;
struct edge{int u,v,nxt,w;}E[M<<1],E0[M<<1];
int h[N],cc;
void add(int u,int v,int z) {E[cc].v=v;E[cc].w=z;E[cc].nxt=h[u];h[u]=cc;++cc;
}
bool cmp(edge a,edge b) {return a.w > b.w;}
int n,m;
int f[N][22],mn[N][22],fa[N];
int find(int x) {if(x==fa[x])return x;return fa[x]=find(fa[x]);
}
void merge(int x,int y) {x=find(x), y =find(y);if(x!=y) fa[x]=y;
}
void krus() {sort(E0+1,E0+1+m,cmp);rep(i,1,m) {int tx = find(E0[i].u), ty = find(E0[i].v);if(tx!=ty) {merge(tx,ty);add(E0[i].u,E0[i].v,E0[i].w);add(E0[i].v,E0[i].u,E0[i].w);}}
}
bool vis[N];
int dep[N];
void dfs(int u,int pre) {vis[u] = 1;f[u][0] = pre;for(int i=h[u];~i;i=E[i].nxt) {int v = E[i].v;if(!vis[v]&&v!=pre) {dep[v]=dep[u]+1;mn[v][0] = E[i].w;dfs(v,u);for(int j=1;j<=20;++j) f[v][j] = f[f[v][j-1]][j-1];for(int j=1;j<=20;++j) mn[v][j] = min(mn[v][j-1],mn[f[v][j-1]][j-1]);}}
}
void init() {memset(mn,inf,sizeof(mn));krus();rep(i,1,n)if(!vis[i])dfs(i,0);
// rep(i,1,n) {
// printf("%d :\n",i);
// printf("dep[%d] = %d\n",i,dep[i]);
// rep(j,0,3) printf("fa[%d][%d] = %d\n",i,j,f[i][j]);
// rep(j,0,3) printf("mn[%d][%d] = %d\n",i,j,mn[i][j]);
// }
}
int lca(int x,int y) {if(dep[x] > dep[y]) swap(x,y);int tx=x,ty=y;for(int d=dep[y]-dep[x],i=0;d;d>>=1,++i) if(d&1) ty = f[ty][i];if(tx == ty) return tx;for(int i=20;i>=0;--i) {if(f[tx][i]==f[ty][i]) continue;tx = f[tx][i], ty = f[ty][i];}return f[tx][0];
}
int ask_mn(int x,int p) {int ans = inf, tx=x;for(int d=dep[x]-dep[p],i=0;d;d>>=1,++i) if(d&1) {ans = min(ans,mn[tx][i]);tx = f[tx][i];}return ans;
}
int ask(int x,int y) {if(find(x)!=find(y)) return -1;int LCA = lca(x,y);return min(ask_mn(x,LCA),ask_mn(y,LCA));
}
int main() {n = read(), m =read();rep(i,1,n) h[i]=-1,fa[i]=i;rep(i,1,m) E0[i].u=read(),E0[i].v=read(),E0[i].w=read();init();int q = read();while(q--) {int x=read(), y =read();printf("%d\n",ask(x,y));}return 0;
}
//9 8
//1 2 4
//1 5 3
//2 3 3
//2 4 2
//3 9 2
//3 8 7
//5 7 6
//5 6 7