[洛谷 P1967]货车运输

danihao123 posted @ 2016年4月10日 18:27 in 题解 with tags NOIP 并查集 MST 洛谷 倍增LCA , 623 阅读
转载请注明出处:http://danihao123.is-programmer.com/

倍增LCA经典题……

这题的做法就是求最大生成树,然后用倍增LCA法求瓶颈路……

注意一下,两点不连通时输出-1(其实这个用并查集判断不就行了……)!!!

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=10001,maxm=50001,maxlogn=15;
int n,m;

// edgeStruct
struct Edge{
    int u,v,d;
    friend bool operator < (const Edge& a,const Edge& b){
        return a.d>b.d;
    }
};
Edge EdgePool[maxm];

// Graph
vector<Edge> edges;
vector<int> G[maxn];
inline void Add_Edge(int x,int y,int c){
    edges.push_back((Edge){x,y,c});
    edges.push_back((Edge){y,x,c});
    int m=edges.size();
    G[x].push_back(m-2);
    G[y].push_back(m-1);
}

// DJ Set
int p[maxn],rank[maxn];
int find_set(int x){
    if(p[x]==x)
        return x;
    else
        return p[x]=find_set(p[x]);
}
void link_set(int x,int y){
    if(rank[x]>rank[y]){
        p[y]=x;
    }else{
        p[x]=y;
        if(rank[x]==rank[y])
            rank[y]++;
    }
}
inline void union_set(int x,int y){
    link_set(find_set(x),find_set(y));
}
inline bool is_same(int x,int y){
    return find_set(x)==find_set(y);
}
inline void init_dj_set(){
    register int i;
    for(i=1;i<=n;i++)
        p[i]=i;
}

// MST
inline void mst(){
    register int i,k=0;
    sort(EdgePool,EdgePool+m);
    init_dj_set();
    for(i=0;i<m;i++){
        Edge& e=EdgePool[i];
        if(!is_same(e.u,e.v)){
            Add_Edge(e.u,e.v,e.d);
            union_set(e.u,e.v);
            k++;
            if(k==(n-1))
                break;
        }
    }
}

// DFS & LCA
int dep[maxn],par[maxn][maxlogn],mincost[maxn][maxlogn];
void dfs(int x,int depth,int fa){
    int i;
    dep[x]=depth;
    par[x][0]=fa;
    for(i=0;i<G[x].size();i++){
        Edge& e=edges[G[x][i]];
        if(e.v!=fa){
            mincost[e.v][0]=e.d;
            dfs(e.v,depth+1,x);
        }
    }
}
inline void init_LCA(){
    register int i,j,anc;
    for(j=1;(1<<j)<=n;j++)
        for(i=1;i<=n;i++)
            if(par[i][j-1]!=-1){
                anc=par[i][j-1];
                par[i][j]=par[anc][j-1];
                mincost[i][j]=min(mincost[i][j-1],mincost[anc][j-1]);
            }
}
int query(int x,int y){
    register int j,log,ans=0x4fffffff;
    if(dep[x]<dep[y])
        swap(x,y);
    for(log=1;(1<<log)<=dep[x];log++);
    log--;
    for(j=log;j>=0;j--)
        if((dep[x]-(1<<j))>=dep[y]){
            ans=min(ans,mincost[x][j]);
            x=par[x][j];
        }
    if(x==y)
        return ans;
    for(j=log;j>=0;j--)
        if(par[x][j]!=-1 && par[x][j]!=par[y][j]){
            ans=min(ans,mincost[x][j]);
            ans=min(ans,mincost[y][j]);
            x=par[x][j];
            y=par[y][j];
        }
    ans=min(ans,min(mincost[x][0],mincost[y][0]));
    return ans;
}
int main(){
    register int i;
    int a,b,c,q;
    scanf("%d%d",&n,&m);
    for(i=0;i<m;i++){
        scanf("%d%d%d",&a,&b,&c);
        EdgePool[i].u=a;
        EdgePool[i].v=b;
        EdgePool[i].d=c;
    }
    memset(par,-1,sizeof(par));
    mst();
    dfs(1,1,0);
    init_LCA();
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&a,&b);
        if(is_same(a,b)){
            printf("%d\n",query(a,b));
        }else{
            puts("-1");
        }
    }
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter