牛客国庆集训派对Day6 J - LCA+生成树

版权声明:欢迎随便转载。 https://blog.csdn.net/a1214034447/article/details/82988775

题目链接:点击这里

解题思路:

因为边最多是点的+100,所以我们先生成一个生成树,然后剩下最多100个边.如果最小解不在生成树上面,那么最小解肯定会经过剩余100个边的某个端点,那么接下来把这剩下100个边的每个边拿去一个端点跑bfs(长度为1直接bfs)最短路,最后把生成树上面的最短路,和100个端点的最短路取最小就行了.

#include<bits/stdc++.h>
using namespace std;
const int mx = 1e5 + 5;
int n,m,head[mx],tot,dep[mx];
int q[mx],tail,fa[mx][20];
int dis[105][mx],que[mx];
bool vis[mx];
struct node
{
    int y,nxt;
}edge[2*mx+200];
void AddEdge(int x,int y)
{
    edge[tot] = {y,head[x]};
    head[x] = tot++;
    edge[tot] = {x,head[y]};
    head[y] = tot++;
}
void dfs(int x,int f)
{
    vis[x] = 1;
    dep[x] = dep[f] + 1;
    fa[x][0] = f;
    for(int i=head[x];~i;i=edge[i].nxt)
    {
        int u = edge[i].y;
        if(u==f||vis[u]) continue;
        dfs(u,x);
    }
}
void RMQ(int N){//RMQfa[i]的2^j祖先
    for(int j=1;(1<<j)<=N;j++)
    for(int i=1;i<=N;i++)
    fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int u,int v){
    if(dep[u]<dep[v])  swap(u,v);
    int i,j;
    i=log(dep[u])/log(2.0);
    for(j=i;j>=0;j--)
    if((dep[u]-(1<<j))>=dep[v])
    u=fa[u][j];//使u和v相同深度
    if(u==v)  return u;
    for(j=i;j>=0;j--){
        if(fa[u][j]!=fa[v][j]){//不断逼近
            u=fa[u][j];
            v=fa[v][j];
        }
    }
    return fa[u][0];
}
void bfs(int* d,int x)
{
    int h = 0,t = 1,tmp;
    que[0] = x;
    while(h!=t){
        tmp = que[h++];
        for(int i=head[tmp];~i;i=edge[i].nxt)
        {
            int u = edge[i].y;
            if(d[u]||u==x) continue;
            d[u] = d[tmp] + 1;
            que[t++] = u;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int a,b;
    memset(head,-1,sizeof(head));
    for(int i=0;i<m;i++){
        scanf("%d%d",&a,&b);
        AddEdge(a,b);
    }
    dfs(1,0),RMQ(n);
    for(int i=0;i<tot;i+=2)
    {
        a = edge[i].y;
        b = edge[i+1].y;
        if(dep[a]+1!=dep[b]&&dep[b]+1!=dep[a])
        q[tail++] = a;
    }
    sort(q,q+tail);
    tail = unique(q,q+tail) - q;
    for(int i=0;i<tail;i++)  bfs(dis[i],q[i]);
    scanf("%d",&m);
    while(m--){
        scanf("%d%d",&a,&b);
        int ans = dep[a] + dep[b] - 2*dep[LCA(a,b)];
        for(int i=0;i<tail;i++)
        ans = min(ans,dis[i][a]+dis[i][b]);
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1214034447/article/details/82988775