Uva 11354 LCA 倍增祖先

题目链接:https://vjudge.net/contest/144221#problem/B

题意:找一条从 s 到 t  的路,使得瓶颈路最小。

点的数目是10^4,如果向之前的方案求 maxcost数组,O(n*n)时间是过不了的,这个时候,用到了增倍祖先。

关于倍增祖先:http://m.w2bc.com/article/177601

我要补充的是,倍增祖先的优点,是在于倍增,他写的案例,没有体现出倍增,这里强调一下。有点像二分的思想;

利用倍增祖先初始化maxcost[i][j]数组,maxcost[i][j] 在倍增祖先里面表示的,结点 i 的第2j级祖先之间的瓶颈。

用O(nlogn)初始化,然后,查询是O(logn)。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 50000 + 10;
const int INF = 0x3f3f3f3f;
const int logmaxn = 20;

int n,m;

struct Edge
{
    int u,v,d;
    bool operator < (const Edge& rhs) const
    {
        return d < rhs.d;
    }
};

Edge e[maxn];

int pa[maxn];

int Find_Set(int x)
{
    if(x!=pa[x])
        pa[x] = Find_Set(pa[x]);
    return pa[x];
}

vector<int> G[maxn],C[maxn];


struct LCA
{
    int n;
    int fa[maxn];
    int cost[maxn];
    int L[maxn];
    int anc[maxn][logmaxn];
    int maxcost[maxn][logmaxn];

    void preprocess()
    {
        for(int i=0; i<n; i++)
        {
            anc[i][0] = fa[i];
            maxcost[i][0] = cost[i];
            for(int j=1; (1<<j)<n; j++)
                anc[i][j] = -1;
        }

        for(int j=1; (1<<j)<n; j++)
        {
            for(int i=0; i<n; i++)
            {
                if(anc[i][j-1]!=-1)
                {
                    int a = anc[i][j-1];
                    anc[i][j] = anc[a][j-1];
                    maxcost[i][j] = max(maxcost[i][j-1],maxcost[a][j-1]);
                }
            }
        }
    }

    int query (int p,int q)
    {
        int log;
        if(L[p]<L[q]) swap(p,q);
        for(log=1; (1<<log)<=L[p]; log++);
        log--;

        int ans = -INF;
        for(int i=log; i>=0; i--)
        {
            if(L[p]-(1<<i)>=L[q])
            {
                ans = max(ans,maxcost[p][i]);
                p = anc[p][i];
            }
        }
        if(p==q) return ans;        //lca 是 p

        for(int i=log; i>=0; i--)
        {
            if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i])
            {
                ans = max(ans,maxcost[p][i]);
                p = anc[p][i];
                ans = max(ans,maxcost[q][i]);
                q = anc[q][i];
            }
        }

        ans = max(ans,cost[p]);
        ans = max(ans,cost[q]);

        return ans;
        //LCA 是 fa[p] = fa[q];
    }

};

LCA solver;

void dfs(int u,int fa,int level)
{
    solver.L[u] = level;
    for(int i=0; i<G[u].size(); i++)
    {
        int v = G[u][i];
        if(G[u][i]!=fa)
        {
            solver.fa[v] = u;
            solver.cost[v] = C[u][i];
            dfs(G[u][i],u,level+1);
        }
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    int kase = 1;
    while(scanf("%d%d",&n,&m)==2&&n)
    {
        for(int i=0; i<m; i++)
        {
            int u,v,d;
            scanf("%d%d%d",&u,&v,&d);
            u--;
            v--;
            e[i] = (Edge)
            {
                u,v,d
            };
        }
        sort(e,e+m);

        for(int i=0; i<n; i++)
        {
            pa[i] = i;
            G[i].clear();
            C[i].clear();
        }

        for(int i=0; i<m; i++)
        {
            int u = e[i].u;
            int v = e[i].v;
            int fx = Find_Set(u);
            int fy = Find_Set(v);

            if(fx!=fy)
            {
                pa[fx] = fy;
                G[u].push_back(v);
                C[u].push_back(e[i].d);
                G[v].push_back(u);
                C[v].push_back(e[i].d);
            }
        }
        solver.n = n;
        dfs(0,-1,0);
        solver.preprocess();
        if(kase++!=1)
            puts("");
        int Q;
        scanf("%d",&Q);
        while(Q--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            u--;
            v--;
            printf("%d
",solver.query(u,v));
        }

    }

    return 0;
}
原文地址:https://www.cnblogs.com/TreeDream/p/6146513.html