[NOIP 2013] 货车运输

[题目链接]

           https://www.luogu.org/problemnew/show/P1967

[算法]

        可以证明答案一定为最大生成树上两点路径中的最小值

        树上倍增即可

        时间复杂度 : O((N + Q) log N)
[代码]

         

#include<bits/stdc++.h>
using namespace std;
#define MAXN 10010
#define MAXM 50010
#define MAXLOG 20
const int inf = 2e9;

struct info
{
    int u,v,w;
} a[MAXM];
struct edge
{
    int to,w,nxt;
} e[MAXM << 1];

int i,n,m,u,v,w,x,y,tot,cnt,q;
int fa[MAXN],color[MAXN],head[MAXN],depth[MAXN];
int anc[MAXN][MAXLOG],mn[MAXN][MAXLOG];
bool visited[MAXN];

namespace IO
{
    template <typename T> inline void read(T &x)
    {
        int f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar())
        {
            if (c == '-') f = -f;
        }
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    template <typename T> inline void write(T x)
    {
        if (x < 0)
        {
            putchar('-');
            x = -x;
        }
        if (x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
    template <typename T> inline void writeln(T x)
    {
        write(x);
        puts("");
    }
} ;
inline bool cmp(info a,info b)
{
    return a.w > b.w;
}
inline void addedge(int u,int v,int w)
{
    tot++;
    e[tot] = (edge){v,w,head[u]};
    head[u] = tot;
}
inline int get_root(int x)
{
    if (fa[x] == x) return x;
    return fa[x] = get_root(fa[x]);
}
inline void kruskal()
{
    int i,su,sv,u,v,w;
    sort(a + 1,a + m + 1,cmp);
    for (i = 1; i <= m; i++)
    {
        u = a[i].u; v = a[i].v; w = a[i].w;
        su = get_root(u);
        sv = get_root(v);
        if (su != sv) 
        {
            fa[sv] = su;
            addedge(u,v,w);
            addedge(v,u,w);
        }
    }
}
inline void dfs(int u,int id)
{
    int i,v,w;
    color[u] = id;
    visited[u] = true;
    for (i = 1; i < MAXLOG; i++)
    {
        anc[u][i] = anc[anc[u][i - 1]][i - 1];
        mn[u][i] = min(mn[u][i - 1],mn[anc[u][i - 1]][i - 1]);
    }
    for (i = head[u]; i; i = e[i].nxt)    
    {
        v = e[i].to;
        w = e[i].w;
        if (!visited[v]) 
        {
            depth[v] = depth[u] + 1;
            anc[v][0] = u;
            mn[v][0] = w;
            dfs(v,id);
        }
    }
}
inline int query(int x,int y)
{
    int i,t;
    int ret = inf;
    if (color[x] != color[y]) return -1;
    if (depth[x] > depth[y]) swap(x,y);
    t = depth[y] - depth[x];
    for (i = 0; i < MAXLOG; i++)
    {
        if (t & (1 << i))
        {
            ret = min(ret,mn[y][i]);
            y = anc[y][i];
        }
    }
    if (x == y) return ret;
    for (i = MAXLOG - 1; i >= 0; i--)
    {
        if (anc[x][i] != anc[y][i])
        {
            ret = min(ret,min(mn[x][i],mn[y][i]));
            x = anc[x][i];
            y = anc[y][i];
        }
    } 
    if (depth[x] == 0) return ret;
    ret = min(ret,min(mn[x][0],mn[y][0]));
    return ret;
}

int main()
{
    
    IO :: read(n); IO :: read(m);
    for (i = 1; i <= m; i++)
    {
        IO :: read(a[i].u); IO :: read(a[i].v);
        IO :: read(a[i].w);
    }
    for (i = 1; i <= n; i++) fa[i] = i;
    kruskal();
    for (i = 1; i <= n; i++)
    {
        if (!visited[i]) 
            dfs(i,++cnt);
    }
    IO :: read(q);
    while (q--)
    {
        IO :: read(x); IO :: read(y);
        IO :: writeln(query(x,y));    
    }
    
    return 0;
}

        

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9463729.html