您的位置:首页 > 其它

noip2013 货车运输

2018-10-10 18:21 375 查看

题目描述

A国有nn座城市,编号从 11到nn,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入输出格式

输入格式:

 

第一行有两个用一个空格隔开的整数n,mn,m,表示 AA 国有nn 座城市和 mm 条道路。

接下来 mm行每行33个整数 x, y, zx,y,z,每两个整数之间用一个空格隔开,表示从 xx号城市到yy号城市有一条限重为 zz 的道路。注意: xx 不等于 yy,两座城市之间可能有多条道路 。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y 。

 

输出格式:

 

共有 qq 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1−1。

 

根据题目得知,我们可以不用考虑路径有多长,只用考虑是否能到以及经过路径的最大值。

这样我们可以把原图化简为一个最大生成树,保证原图能到达的点,化简后也能到达。

然后对于每一个x、y,只用求出它们的路径中间的最小值就可以了。用LCA就行

但是!我们发现,输入的图不一定是联通的!也就是,我们生成的不一定是最大生成树而是最大生成森林!

这样,我们跑LCA会原地爆炸!

故此,我们可以在构建完最大森林后,将所有森林的根节点连到一个虚拟节点0,。

如果LCA时,发现两个的LCA是0,那么就输出-1.

 

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define REP(i,k,n) for(int i=k;i<=n;i++)
#define in(a) a=read()
#define MAXN 500010
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
f=-1;
for(;isdigit(ch);ch=getchar())
x=x*10+ch-'0';
return x*f;
}
int n,m,p,ans;
int f[MAXN];
queue <int> Q;
int total=0,head[MAXN],to[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1];
int vis[MAXN],depth[MAXN];
int tree[MAXN][30],minn[MAXN][30];
struct node{
int a,b,c;
}l[MAXN];
inline bool cmp(node a,node b){
return a.c>b.c;
}
inline int getf(int k){//并查集求最大生成森林
if(f[k]==k)  return k;
return f[k]=getf(f[k]);
}
inline void adl(int a,int b,int c){
total++;
to[total]=b;
val[total]=c;
nxt[total]=head[a];
head[a]=total;
return ;
}
inline void bfs(){//LCA预处理
Q.push(0);
vis[0]=1;
while(!Q.empty()){
int u=Q.front();
Q.pop();
REP(i,1,18)
tree[u][i]=tree[tree[u][i-1]][i-1],minn[u][i]=min(minn[u][i-1],minn[tree[u][i-1]][i-1]);
for(int e=head[u];e;e=nxt[e])
if(!vis[to[e]]){
vis[to[e]]=1;
depth[to[e]]=depth[u]+1;
tree[to[e]][0]=u;
minn[to[e]][0]=val[e];
Q.push(to[e]);
}
}
return ;
}
inline int lca(int u,int v){//跑LCA
if(depth[u]<depth[v])  swap(u,v);
int d=depth[u]-depth[v];
REP(i,0,18)
if(d&(1<<i)){
ans=min(ans,minn[u][i]);
u=tree[u][i];
}
if(u==v)  return u;
for(int i=18;i>=0;i--)
if(tree[u][i]!=tree[v][i]){
ans=min(ans,min(minn[u][i],minn[v][i]));
u=tree[u][i];
v=tree[v][i];
}
ans=min(ans,min(minn[u][0],minn[v][0]));
u=tree[u][0];
v=tree[v][0];
return u;
}
int main(){
in(n);in(m);
REP(i,1,n)  f[i]=i;
REP(i,1,m)
in(l[i].a),in(l[i].b),in(l[i].c);
sort(l+1,l+m+1,cmp);
REP(i,1,m){
int f1=getf(l[i].a),f2=getf(l[i].b);
if(f1!=f2){
adl(l[i].a,l[i].b,l[i].c);
adl(l[i].b,l[i].a,l[i].c);
f[f2]=f1;
}
}
REP(i,1,n)//构建虚拟节点
if(!vis[i]){
adl(0,i,0);
bfs();//对于森林里的每一颗树都跑一边预处理
}
in(p);
int u,v;
REP(i,1,p){
ans=2147483647;
in(u),in(v);
if(lca(u,v))  cout<<ans<<endl;
else  cout<<"-1"<<endl;
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: