1. 程式人生 > >洛谷1967貨物運輸(kruskal+lca倍增)

洛谷1967貨物運輸(kruskal+lca倍增)

題目描述

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 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
輸出樣例#1:
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。

【思路】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>