洛谷 P1967 货车运输 LCA + 最小生成树

 两点之间边权最大值的最小值一定在图的最小生成树中取到。

求出最小生成树,进行倍增即可。

Code:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 10000 + 3;
const int maxm = 100000 + 3;
const int inf  = 10000000+3;
const int logn = 30;
int st[maxm], ed[maxm], cost[maxm];
int head[maxm],to[maxm<<1], nex[maxm<<1], val[maxm<<1], cnt;
int F[maxn][logn], minv[maxn][logn], dep[maxn];
int n,m;
int cmp(int i,int j)
{
    return cost[i] > cost[j];
}
struct Make_Tree
{
    int A[maxm],p[maxn];
    int find(int x)
    {
        return p[x] == x ? x : p[x] = find(p[x]);
    }
    inline void add_edge(int u,int v,int c)
    {
        nex[++cnt] = head[u], head[u] = cnt, to[cnt] = v, val[cnt] = c;
    }
    inline void solve()
    {
        for(int i = 1;i <= m;++i)A[i] = i;
        for(int i = 1;i <= n;++i)p[i] = i;
        sort(A+1,A+1+m,cmp);
        for(int i = 1;i <= m;++i)
        {
            int cur = A[i];  
            int a = st[cur], b = ed[cur];
            int x = find(a);
            int y = find(b);
            if(x == y)continue;
            add_edge(a,b,cost[cur]);
            add_edge(b,a,cost[cur]);
            p[x] = y;
        }
    }
}T;      
void dfs(int u,int fa,int c,int deep)
{
    F[u][0] = fa, minv[u][0] = c, dep[u] = deep;
    for(int v = head[u]; v ;v = nex[v])
        if(to[v] != fa){
            dfs(to[v],u,val[v],deep+1);
        }
}
inline int solve(int a,int b)
{
    if(dep[a] > dep[b])swap(a,b);
    int ans = inf;
    if(dep[b] != dep[a])
    {
        for(int i =logn-1;i>=0;--i)
           if(dep[a] <= dep[F[b][i]])
            {
               ans = min(ans,minv[b][i]);
               b = F[b][i];
            }
    }
    if(a == b)return ans;
    for(int i = logn-1;i>=0;--i)
    if(F[a][i] != F[b][i]) 
    {
        ans = min(ans,min(minv[a][i],minv[b][i]));
        a = F[a][i], b = F[b][i];
    }
    ans = min(ans,min(minv[a][0],minv[b][0]));
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
        scanf("%d%d%d",&st[i],&ed[i],&cost[i]);
    T.solve();
    for(int i = 1;i <= n;++i) 
        if(!dep[i])dfs(i,0,0,1);
    for(int i = 1;i < logn-1;++i)
        for(int j = 1;j <= n;++j)
        {
            minv[j][i] = min(minv[j][i-1], minv[F[j][i-1]][i-1]);
            F[j][i] = F[F[j][i-1]][i-1];
        }
    int asks;
    scanf("%d",&asks);
    for(int i = 1;i <= asks;++i)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(T.find(a) != T.find(b) || a>n|| b>n)printf("-1\n");
        else printf("%d\n",solve(a,b));
    }
    return 0;
}

  

posted @ 2018-10-17 00:07  EM-LGH  阅读(152)  评论(0编辑  收藏  举报