您的位置:首页 > 其它

【NOIP2013】Day1T3 货车运输

2016-10-30 03:10 239 查看

货车运输

Description

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

Input Format

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

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

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

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

Output Format

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

Sample Input

4 3

1 2 4

2 3 3

3 1 1

3

1 3

1 4

1 3

Sample Output

3

-1

3

Hint

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;

对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;

对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

分析

有一种东西叫做最小瓶颈路,是指在两个结点之间求一条最长边最短的路径。而题目要求的是结点间最短边最长,我们可以用最小瓶颈路的方法求解。

首先,对于30%的数据,可以直接暴力Spfa求出每对结点的最短边。

其次,考虑一个应该算是贪心的东西,最终答案一定是在最大生成树上(证明:假设完全不在最大生成树上,那么可以在最大生成树上找到一条路径使得最长边最短;若一部分在最大生成树上且最短边在内,则答案相等,最短边不在内,则在最大生成树上的边都比这条最短边大)。所以我们可以建一颗最大生成树,然后找出每对结点间的路径。

然后,我们发现如果对于每个询问直接跑一遍树求结点间最短边,复杂度为O(mlogm∗qn) ,只能处理60%的数据。因为是树上的问题,我们可以用树上倍增的方法来维护最短边。对于每个询问找出最近公共祖先,在寻找的同时处理答案即可,复杂度降为O(mlogm∗qlogn) 。

#include <cstdio>
#include <algorithm>
using namespace std;
int tot,n,m,q,u,v,last[10001],father[10001],dep[10001],fa[10001][21],val[10001][21];
struct info{
int to,next,val;
}e[1000000];
struct data{
int u,v,w;
}edge[50001];
void addline(int u,int v,int c){
e[++tot].to=v; e[tot].next=last[u]; last[u]=tot; e[tot].val=c;
e[++tot].to=u; e[tot].next=last[v]; last[v]=tot; e[tot].val=c;
}
inl
4000
ine bool cmp(const data&a,const data&b){
return a.w>b.w;
}
int getfather(int x){
return x==father[x]?x:father[x]=getfather(father[x]);
}
void getdeep(int u,int father){
fa[u][1]=father;
for (int i=2;i<=20;i++){
fa[u][i]=fa[fa[u][i-1]][i-1];
val[u][i]=min(val[fa[u][i-1]][i-1],val[u][i-1]);
}
dep[u]=dep[father]+1;
for (int i=last[u];i;i=e[i].next){
if (father==e[i].to) continue;
val[e[i].to][1]=e[i].val;
getdeep(e[i].to,u);
}
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) father[i]=i;
for (int i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
sort(edge+1,edge+1+m,cmp);
for (int i=1;i<=m;i++){
int fu=getfather(edge[i].u),fv=getfather(edge[i].v);
if (fu!=fv){
father[fu]=fv;
addline(edge[i].u,edge[i].v,edge[i].w);
if (tot==2*(n-1)) break;
}
}
getdeep(1,0);
for (scanf("%d",&q);q;q--){
scanf("%d%d",&u,&v);
if (getfather(u)!=getfather(v)){
printf("-1\n");
continue;
}
int minu=1<<30,minv=1<<30;
if (dep[u]<dep[v]) swap(u,v);
for (int i;dep[u]!=dep[v];u=fa[u][i]){
for (i=20;dep[fa[u][i]]<dep[v];i--);
minu=min(minu,val[u][i]);
}
for (int i;u!=v;u=fa[u][i],v=fa[v][i]){
for (i=20;fa[u][i]==fa[v][i] && i>1;i--);
minu=min(minu,val[u][i]);
minv=min(minv,val[v][i]);
}
printf("%d\n",min(minu,minv));
}
fclose(stdin); fclose(stdout);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: