题目
题目描述
AA国有n n座城市,编号从 1 1到 nn,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入格式
第一行有两个用一个空格隔开的整数 n,mn,m,表示 AA 国有 nn 座城市和 mm 条道路。
接下来 mm行每行 3 3个整数 x, y, zx,y,z,每两个整数之间用一个空格隔开,表示从 x x号城市到 y y号城市有一条限重为 zz 的道路。注意: ** xx 不等于 yy,两座城市之间可能有多条道路 ** 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: ** x 不等于 y ** 。
输出格式
共有 qq 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1−1。
输入输出样例
输入
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
输出
3
-1
3
说明/提示
对于 30%30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q< 1,0000<n<1,000,0<m<10,000,0<q<1,000;
对于 60%60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<n<1,000,0<m<50,000,0<q<1,000;
对于 100%100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,0000<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,000。
算法 最大生成树+树链剖分(边权)
最大生成树的算法其实就是最小生成树的算法
用最大生成树的原因:
货车要从一个地点到另一个点要经过的道路应尽可能大,所以那些多余的路径就可以删去,
而且树上任意两点可以相互到达。
接下来问题就变成了 找两点最短路径之间边权的最小值
惊奇地发现可以用树链剖分来维护两点间最短路径的最短边权。
代码
#include<bits/stdc++.h>
using namespace std;
const int ll=5e5+5,maxn=1e5+5;
int n,m,s;
int uer[ll],ver[ll],wer[ll],f[ll],tot;
int head[ll],next[ll];
void add(int u,int v,int w){
tot++;
ver[tot]=v;
wer[tot]=w;
next[tot]=head[u];
head[u]=tot;
}
struct lcj{
int a,b,c;
}bian[ll];
bool cmp(lcj x,lcj y){
return x.c>y.c;
}
int get(int x){
if(f[x]==x) return x;
f[x]=get(f[x]);
return f[x];
}
void hb(int x,int y){
int t1=get(x),t2=get(y);
if(t1!=t2){
f[t1]=t2;
}
}
int top[maxn],d[maxn],son[maxn],size[maxn],fa[maxn],dfn[maxn],pre[maxn],val[maxn],cnt,book[maxn];
void dfs1(int u,int f){
book[u]=1;
d[u]=d[f]+1;
fa[u]=f;
size[u]=1;
for(int i=head[u];i;i=next[i]){
int v=ver[i],w=wer[i];
if(v==f) continue;
dfs1(v,u);
size[u]+=size[v];
val[v]=w;
if(son[u]==-1||size[son[u]]<size[v])
son[u]=v;
}
}
void dfs2(int u,int tp){
book[u]=1;
dfn[u]=++cnt;
pre[cnt]=u;
top[u]=tp;
if(son[u]==-1) return ;
if(son[u])
dfs2(son[u],tp);
for(int i=head[u];i;i=next[i]){
int v=ver[i];
if(v==son[u]||v==fa[u]) continue;
dfs2(v,v);
}
}
struct node{
int l,r,data;
}t[maxn<<2];
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].data=val[pre[l]];
return ;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build((p<<1)|1,mid+1,r);
t[p].data=min(t[p<<1].data,t[(p<<1)|1].data);
}
int getmin(int p,int l,int r){
if(l<=t[p].l&&r>=t[p].r){
return t[p].data;
}
int mid=t[p].l+t[p].r>>1,ans=99999999;
if(l<=mid) ans=min(ans,getmin(p<<1,l,r));
if(r>mid) ans=min(ans,getmin((p<<1)|1,l,r));
return ans;
}
int ask(int x,int y){
int ans=99999999;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
ans=min(ans,getmin(1,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(x==y) return ans;
if(d[x]>d[y]) swap(x,y);
ans=min(ans,getmin(1,dfn[x]+1,dfn[y]));
return ans;
}
int main(){
memset(son,-1,sizeof(son));
memset(val,0x3f3f,sizeof(val));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&bian[i].a,&bian[i].b,&bian[i].c);
sort(bian+1,bian+m+1,cmp);
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
int u=bian[i].a,v=bian[i].b,w=bian[i].c;
int t1=get(u),t2=get(v);
if(t1==t2) continue;
hb(t1,t2);
add(u,v,w);
add(v,u,w);
}
for(int i=1;i<=n;i++)
if(!book[i])
dfs1(i,0);
memset(book,0,sizeof(book));
for(int i=1;i<=n;i++)
if(!book[i])
dfs2(i,i);
build(1,1,n);
scanf("%d",&s);
while(s--){
int x,y;
scanf("%d%d",&x,&y);
if(get(x)!=get(y)){
printf("-1\n");
continue;
}
printf("%d\n",ask(x,y));
}
return 0;
}