您的位置:首页 > 其它

noip2013货车运输

2016-10-09 17:34 330 查看

LCA初步: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。

输出格式

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

样例输入

4 3

1 2 4

2 3 3

3 1 1

3

1 3

1 4

1 3

样例输出

3

-1

3

提示

对于 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%就直接爆搜,60%用并查集弄最大生成树后找两个点连接的不同路径中每条路径的最小值的最大值(有点绕……),100%思想和60%一样但需用到LCA

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
int a,b,w;
}gg[50005];
int head[10005],tov[20005],ne[20005],w[20005],fat[10005];
int tot,fa[10005][20],dis[10005][18],deep[10005];
bool judge[10005];
void add(int a,int b,int z)
{
tov[++tot]=b;
ne[tot]=head[a];
w[tot]=z;
head[a]=tot;
}
int cmp(const node&a,const node&b)
{
return a.w>b.w;
}
int find(int x)
{
if(x!=fat[x])return fat[x]=find(fat[x]);
return fat[x];
}
void dfs(int k)
{
judge[k]=true;
for(int i=1;i<=16;i++)
{
if(deep[k]<(1<<i))break;
fa[k][i]=fa[fa[k][i-1]][i-1];
dis[k][i]=min(dis[k][i-1],dis[fa[k][i-1]][i-1]);//这道题条件
}
int t=head[k];
while(tov[t])
{
if(!judge[tov[t]])
{
fa[tov[t]][0]=k;
dis[tov[t]][0]=w[t];
deep[tov[t]]=deep[k]+1;
dfs(tov[t]);
}
t=ne[t];
}
}
int lca(int a,int b)
{
if(deep[a]<deep[b])
swap(a,b);
int t=deep[a]-deep[b];
for(int i=0;i<=16;i++)//16到0也可以
if((1<<i)&t)
a=fa[a][i];//只跳二进制数t中有1的位数,保证刚好跳t
for(int i=16;i>=0;i--)
if(fa[a][i]!=fa[b][i])//不跳过
{
a=fa[a][i];
b=fa[b][i];
}
if(a==b)return b;//刚好跳到最近公共祖先
return fa[b][0];//刚好跳到最近公共祖先的下一个
}
int ask(int x,int y)
{
int minx=2100000000;
int t=deep[x]-deep[y];
for(int i=0;i<=16;i++)
{
if(t&(1<<i))
{
minx=min(minx,dis[x][i]);//算x到y的最小值
x=fa[x][i];
}
}
return minx;
}
int main()
{
int n,m;
memset(dis,127/3,sizeof dis);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)   scanf("%d%d%d",&gg[i].a,&gg[i].b,&gg[i].w);
sort(gg+1,gg+m+1,cmp);
for(int i=1;i<=n;i++)
fat[i]=i;
int cnt=0;
for(int i=1;i<=m;i++)
{
int x=gg[i].a,y=gg[i].b;
x=find(x);y=find(y);
if(x!=y)//建最大生成树,两点连通过就不再连
{
fat[x]=y;
add(gg[i].a,gg[i].b,gg[i].w);
add(gg[i].b,gg[i].a,gg[i].w);
cnt++;
if(cnt==n-1)
break;
}
}
for(int i=1;i<=n;i++)
if(!judge[i])
dfs(i);
int q;
scanf("%d",&q);
while(q--)
{
int a,b;
scanf("%d%d",&a,&b);
if(find(a)!=find(b))
{
printf("-1\n");
continue;
}
int f=lca(a,b);
printf("%d\n",min(ask(a,f),ask(b,f)));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  历程