Luogu P1967 货车运输 倍增+最大生成树

看见某大佬在做,决定补一发题解$qwq$


 

首先跑出最大生成树(注意有可能不连通),然后我们要求的就是树上两点间路径上的最小边权。 我们用倍增的思路跑出来$w[u][j]$,表示$u$与的它$2^j$的祖先路径上的最小边权(其实是为了配合$lca$),然后求$lca$时顺便记一下最小边权。

码风清奇别在意是之前写的

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define R register int 
using namespace std;
namespace jack {
    #define N 100010
    #define M 500010
    #define Inf 0x3f3f3f3f
    int n,m,q,cnt,lim,fir[N],dep[N],f[N][20],w[N][20],fa[N];
    bool vis[N];
    struct Edge {
        int u,v,w;
        bool operator < (const Edge& y)const{return w>y.w;}
    }E[M];
    struct edge {int v,w,nxt;}e[M];
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=(ret<<3)+(ret<<1)+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    //inline int min(int a,int b) {return a<b?a:b;}
    inline void add(int u,int v,int w) {e[++cnt].v=v,e[cnt].w=w,e[cnt].nxt=fir[u],fir[u]=cnt;}
    int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
    inline bool merge(int u,int v) {
        R uf=getf(u),vf=getf(v);
        if(uf==vf) return true;
        fa[uf]=vf; return false;
    }
    inline void kruskal() {
        sort(E+1,E+m+1);
        for(R i=1;i<=n;i++) fa[i]=i;
        for(R i=1,u=E[i].u,v=E[i].v,w=E[i].w;i<=m;i++,u=E[i].u,v=E[i].v,w=E[i].w) 
            if(!merge(u,v)) {add(u,v,w),add(v,u,w);}
    }
    void dfs(int u) {
        vis[u]=true;
        for(R i=fir[u];i;i=e[i].nxt) {
            R v=e[i].v; if(dep[v]) continue;
            dep[v]=dep[u]+1;f[v][0]=u,w[v][0]=e[i].w;
            for(R j=1,fa=u;f[fa][j];j++) f[v][j+1]=f[fa][j],fa=f[fa][j];
            dfs(v);
        }
    }
    inline int lca(int u,int v) {
        if(getf(u)!=getf(v)) return -1; R ans=Inf;
        if(dep[u]<dep[v]) swap(u,v);
        for(R i=lim;i>=0;i--) if(dep[f[u][i]]>=dep[v]) ans=min(ans,w[u][i]),u=f[u][i];
        if(u==v) return ans;
        for(R i=lim;i>=0;i--) if(f[u][i]!=f[v][i]) ans=min(ans,min(w[u][i],w[v][i])),u=f[u][i],v=f[v][i];
        return min(ans,min(w[u][0],w[v][0]));
    }
    void main() {
        n=g(),m=g(); lim=log2(n)+1;
        for(R i=1;i<=m;i++) {E[i].u=g(),E[i].v=g(),E[i].w=g();}
        kruskal();
        for(R i=1;i<=n;i++) if(!vis[i]) {dep[i]=1;dfs(i);f[i][0]=i,w[i][0]=Inf;}
        for(R i=1;i<=lim;i++) for(R j=1;j<=n;j++) {
            f[j][i]=f[f[j][i-1]][i-1]; 
            w[j][i]=min(w[j][i-1],w[f[j][i-1]][i-1]);
        } q=g();
        for(int i=1; i<=q; i++) {R u=g(),v=g(); printf("%d\n",lca(u,v));}
    }
}

signed main() {jack::main();}

 

posted @ 2019-06-10 21:11  LuitaryiJack  阅读(128)  评论(0编辑  收藏  举报