uva 11354(倍增法找最近公共祖先+最小生成树)

思路: 其实难点在于如何解决查询的时间复杂度的问题,对于一颗最小生成树,我们可以预先处理出他的anc[][] (倍增父亲)

然后在查询的时候就对于u和v 不断将他们在树上虚拟的向上提,直到提到二者最近公共祖先的直接孩子一级。然后同时记录在“提” 的过程中的最大边。

#include<bits/stdc++.h>

using namespace std;

const int N =5e4+5;
const int M =1e5+5;
const int inf =0x3f3f3f3f;

struct node
{
    int u,v,w;
}E[M];

struct Edge
{
    int to;
    int w;
    int next;
    //Edge(int t,int _w,int _n):to(t),w(_w),next(_n){}
}edge[2*N];

int tot;
int head[N];
int f[N];

void add(int u,int v,int w)
{
    edge[++tot].to=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot;
}

bool cmp(node a,node b)
{
    return a.w<b.w;
}

int getf(int x)
{
    return f[x]==x?x:(f[x]=getf(f[x]));
}

int merge(int u,int v)
{
    int t1=getf(u);
    int t2=getf(v);
    if(t1!=t2)
    {
        f[t2]=t1;
        return 1;
    }
    return 0;
}

int Fa;
int cost[N];
int fa[N];
int L[N];
int anc[N][20];
int maxcost[N][20];
int n,m;

void dfs(int u,int ff,int dep)
{
    L[u]=dep;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(v==ff) continue;
        cost[v]=edge[i].w;
        fa[v]=u;
        dfs(v,u,dep+1);
    }
    return ;
}

void pre_init()
{
    for(int i=1;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=1;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)
{
    if(L[p]<L[q]) swap(p,q);
    int tmp,log;
    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;
    }

    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;
}

void init()
{
    memset(L,0,sizeof(L));
    memset(cost,0,sizeof(cost));
    memset(fa,0,sizeof(fa));
    memset(maxcost,0,sizeof(maxcost));
    memset(anc,0,sizeof(anc));
}

int main()
{
    int ff=0;
    while(cin>>n>>m)
    {
        for(int i=1;i<=m;i++){
            scanf("%d %d %d",&E[i].u,&E[i].v,&E[i].w);
        }

        memset(head,-1,sizeof(head));  tot=0;

        sort(E+1,E+m+1,cmp);
        int cnt=1;
        for(int i=0;i<=n;i++) f[i]=i;
        for(int i=1;i<=m;i++){
            if(merge(E[i].u,E[i].v)){
                add(E[i].u,E[i].v,E[i].w);
                add(E[i].v,E[i].u,E[i].w);
                cnt++;
                if(cnt==n) break;
            }
        }

        init();
        Fa=1;
        dfs(1,-1,0);
        pre_init();

        int q;
        scanf("%d",&q);
        int u,v;
        if(ff) printf("\n");
        while(q--)
        {
            scanf("%d %d",&u,&v);
            printf("%d\n",query(u,v));
        }
        ff=1;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/81051963
今日推荐