货车运输(最大生成树+倍增LCA)

看到第一篇题解的神奇码风……我决定发一篇码风正常的题解造福人类

这题的做法也非常经典,最大生成树\(+LCA\),相当于先贪心一下,在LCA的时候记录一下当前最小的边权

顺便吐槽一下最后一个测试点:

testdata.in
7 8
1 2 2
1 3 5
3 4 4
4 4 2
3 5 3
6 7 4
1 3 3
4 5 8
8
1 2 
1 4 
1 3 
1 5 
1 6 
2 5 
3 5 
6 7
testdata.out
2
4
5
4
-1
2
4
4

回到题面:注意: \(x\)不等于\(y\)两座城市之间可能有多条道路

虽然\(Kruskal\)不会挂掉……但是出题人造数据真不严谨

\(Code\ Below:\)

#include <bits/stdc++.h>
#define INF 99999999
using namespace std;
const int maxn=10000+10;
const int maxm=50000+10;
int n,m,q,head[maxn],f[maxn],tot;
//如题目所示,存储链式前向星和并查集
int fa[maxn][16],w[maxn][16],dep[maxn],rt,t;
//fa[i][j]表示第i个结点向上跳2^i个结点,dep[i]存储第i个结点的深度
struct Edge{
    int x,y,w;
}e[maxm];
struct node{
    int to,next,val;
}tree[maxm<<1];
inline bool cmp(Edge a,Edge b){//cmp
    return a.w>b.w;
}
inline int read(){//读入优化
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
inline void swap(int &a,int &b){int t=a;a=b;b=t;}//交换
inline void add(int x,int y,int w){//存边
    tree[++tot].to=y;
    tree[tot].val=w;
    tree[tot].next=head[x];
    head[x]=tot;
}
int find(int x){//并查集
    if(x!=f[x])
        f[x]=find(f[x]);
    return f[x];
}
inline void Kruskal(){//最大生成树
    for(int i=1;i<=n;i++)
        f[i]=i;
    sort(e+1,e+m+1,cmp);
    int ans=0;
    for(int i=1;i<=m;i++){
        int a=find(e[i].x),b=find(e[i].y);
        if(a!=b){
            f[a]=b;ans++;
            add(e[i].x,e[i].y,e[i].w);
            add(e[i].y,e[i].x,e[i].w);
        }
    }
}
void dfs(int x,int pre,int val){//LCA预处理
    dep[x]=dep[pre]+1;
    w[x][0]=val;
    fa[x][0]=pre;
    for(int i=1;i<=t;i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
        w[x][i]=min(w[x][i-1],w[fa[x][i-1]][i-1]);
    }
    for(int i=head[x];i;i=tree[i].next){
        if(tree[i].to!=pre){
            dfs(tree[i].to,x,tree[i].val);
        }
    }
}
inline int LCA(int x,int y){//倍增LCA
    if(dep[x]<dep[y]) swap(x,y);
    int ans=INF;
    for(int i=t;i>=0;i--)
        if(dep[fa[x][i]]>=dep[y]){
            ans=min(ans,w[x][i]);
            x=fa[x][i];
        }
    if(x==y) return ans;
    for(int i=t;i>=0;i--)
        if(fa[x][i]!=fa[y][i]){
            ans=min(ans,min(w[x][i],w[y][i]));
            x=fa[x][i],y=fa[y][i];
        }
    int val=w[x][0];
    if(fa[x][0]!=y) val=min(val,w[y][0]);
    return min(ans,val);
}

int main()
{
    memset(fa,INF,sizeof(fa));
    memset(w,INF,sizeof(w));
    n=read(),m=read();t=log2(n)+1;
    for(int i=1;i<=m;i++){
        e[i].x=read(),e[i].y=read(),e[i].w=read();
    }
    Kruskal();
    //记住!数据不一定联通!图是一个森林!
    for(int i=1;i<=n;i++)
        if(i==f[i])
            dfs(i,i,INF);
    scanf("%d",&q);
    while(q--){
        int x=read(),y=read();
        //printf("%d %d\n",find(x),find(y));
        if(find(x)!=find(y)) printf("-1\n");
        else printf("%d\n",LCA(x,y));
    }
    return 0;
}
posted @ 2018-08-24 09:51  Owen_codeisking  阅读(564)  评论(3编辑  收藏  举报