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