洛谷1967货物运输(kruskal+lca倍增)

来源:互联网 发布:ip2780清零软件下载 编辑:程序博客网 时间:2024/05/07 07:05

题目描述

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

输入输出格式

输入格式:

输入文件名为 truck.in。
输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道
路。
接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出格式:

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

输入输出样例

输入样例#1:
4 31 2 42 3 33 1 131 31 41 3
输出样例#1:
3-13

说明

对于 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。


【思路】kruskal求最大生成树,发现加入一条边使x,y联通,则该条边的权值为所求。易证。

有一个巧妙的想法,因为边是由大到小加进来的,所以越往上的祖先所管的边权越小,因此我们只要跑一下最大生成树再跑lca便可求解。


【代码】

<span style="font-size:18px;">#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <algorithm>#include <cmath>using namespace std;const int maxn=100005;struct data{    int u,v,w;    bool operator <(const data&b)const{    return(w>b.w);}}e[maxn];int q,n,m,anc[maxn],fa[maxn],cnt=1,num,dep[maxn],f[maxn][19],val[maxn];inline int get(){    char c;while(!isdigit(c=getchar()));    int p=c-48;while(isdigit(c=getchar()))p=p*10+c-48;    return p;}inline int lca(int a,int b){    if(dep[a]<dep[b])swap(a,b);    int j=0;    while((1<<(j+1))<=dep[a])++j;    for(int i=j;i>=0;--i){               //注意i可以取零    if((dep[a]-(1<<i))>=dep[b])a=f[a][i];}if(a==b)return a;for(int i=j;i>=0;--i){    if(f[a][i] && f[a][i]!=f[b][i]){    a=f[a][i];    b=f[b][i];}}return fa[a];}inline int Find(int x){    if(x==anc[x])return anc[x];else return (anc[x]=Find(anc[x])); }int main(){memset(f,0,sizeof(f));memset(fa,0,sizeof(fa));    n=get();m=get();    for(int i=1;i<=m;++i)e[i].u=get(),e[i].v=get(),e[i].w=get();    sort(e+1,e+1+m);num=n;    for(int i=1;i<=n;++i)anc[i]=i;    for(int i=1;i<=m;++i){    int x=Find(anc[e[i].u]);    int y=Find(anc[e[i].v]);    if(x!=y){    anc[x]=anc[y]=fa[x]=fa[y]=++n; //想象一下    fa[n]=0,val[n]=e[i].w,anc[n]=n;    ++cnt;if(cnt==num)break;}}dep[n]=0;for(int i=n-1;i;--i){    dep[i]=dep[fa[i]]+1;    f[i][0]=fa[i];    int j=1;    while(f[f[i][j-1]][j-1])f[i][j]=f[f[i][j-1]][j-1],++j;}q=get();while(q--){    int x=get(),y=get();    if(Find(x)!=Find(y))printf("-1\n");    else printf("%d\n",val[lca(x,y)]);}return 0;}</span>



0 0