kruskal - 倍增 - 並查集 - Luogu 1967 貨車運輸


P1967 貨車運輸

題目描述

A 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,從一個地方到另一個地方最多能運多重的貨物。

說明

對於 100%的數據,0 < 城市數n < 10,000,0 < 道路數m < 50,000,0 < 詢問數q< 30,000,0 ≤ 限重z ≤ 100,000。


鑒於這是個稀疏圖,我們用kruskal。
最小生成樹有一個定理,就是邊集中最大的邊最小
那么我們魔改一下kruskal使它變成求最大生成樹,就有最小邊最大的定理。
之后就可以通過一些手段來處理造出來的生成樹了
樹鏈剖分辣么長,懶得打
所以博主這兒用的倍增
f1[i][j]表示i點往上跳2^j距離到達的點
f2[i][j]表示i點往上跳2^j距離的路徑上的最小值
就可以暴力求LCA辣啊哈哈哈哈
這里推薦一個更快的大佬code-> http://www.cnblogs.com/xzz_233/p/7614189.html .
代碼蒯上

#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gotcha()
{
    register int _a=0;bool _b=1;register char _c=getchar();
    while(_c<'0' || _c>'9'){if(_c=='-')_b=0;_c=getchar();}
    while(_c>='0' && _c<='9')_a=_a*10+_c-48,_c=getchar();
    return _b?_a:-_a;
}
const int _ = 10002;
using namespace std;
struct edge{int to,ne,len;edge(){to=ne=len=0;}}e[10*_];
struct sav
{
    int fr,to,len;sav(){fr=to=len=0;}
    const bool operator < (const sav &b)const{return len>b.len;}
}tp[5*_];
int he[_],ecnt=0,dep[_],f1[_][18],f2[_][18],n,m,fa[_],gfa[_];
void add(int fr,int to,int len)
{e[++ecnt].to=to,e[ecnt].len=len,e[ecnt].ne=he[fr],he[fr]=ecnt;}
int finder(int a){return gfa[a]!=a?gfa[a]=finder(gfa[a]):a;}
void link(int a,int b){gfa[finder(b)]=finder(a);}
void plant(int a)
{
    for(int i=he[a],j;i;i=e[i].ne)
    {
        j=e[i].to;if(j==fa[a])continue;
        fa[j]=a,f1[j][0]=a,f2[j][0]=e[i].len,dep[j]=dep[a]+1,plant(j);
    }
}
int driver(int st,int ta)
{
    register int i,mi=2e9;
    if(dep[st]>dep[ta])
        for(i=16;i>=0;i--)if(f1[st][i]!=0 && dep[f1[st][i]]>=dep[ta])
            mi=min(mi,f2[st][i]),st=f1[st][i];
    if(dep[ta]>dep[st])
        for(i=16;i>=0;i--)if(f1[ta][i]!=0 && dep[f1[ta][i]]>=dep[st])
            mi=min(mi,f2[ta][i]),ta=f1[ta][i];
    if(st==ta)return mi;
    for(i=16;i>=0;i--)if(f1[st][i]!=f1[ta][i])
        mi=min(mi,min(f2[st][i],f2[ta][i])),st=f1[st][i],ta=f1[ta][i];
    return min(mi,min(f2[st][0],f2[ta][0]));
}
int main()
{
    register int i,j,k;
    n=gotcha(),m=gotcha();
    for(i=1;i<=n;i++)gfa[i]=i;
    for(i=1;i<=m;i++)tp[i].fr=gotcha(),tp[i].to=gotcha(),tp[i].len=gotcha();
    sort(tp+1,tp+m+1);
    for(i=1;i<=m;i++)
        if(finder(tp[i].fr)!=finder(tp[i].to))
        {
            link(tp[i].fr,tp[i].to);
            add(tp[i].fr,tp[i].to,tp[i].len),add(tp[i].to,tp[i].fr,tp[i].len);
        }
    for(i=1;i<=n;i++)if(i==gfa[i])fa[i]=i,dep[i]=1,plant(i);
    for(i=1;i<=16;i++)
        for(j=1;j<=n;j++)
        {
            f1[j][i]=f1[f1[j][i-1]][i-1];
            f2[j][i]=min(f2[j][i-1],f2[f1[j][i-1]][i-1]);
        }
    i=gotcha();
    while(i--)
    {
        j=gotcha(),k=gotcha();
        printf("%d\n",(finder(j)==finder(k)?driver(j,k):-1));
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM