最短路LCA

最短路

https://ac.nowcoder.com/acm/problem/19814

在这里插入图片描述
700ms飘过
你可能不相信
我先加了inline
又加了快读。。。
然后TLE->AC
题意:
第一行两个整数n和m,表示图的点数和边数(1≤ n≤ 100000, 1≤ m≤ n+100)。
接下来m行每行两个整数a和b,表示一条边(1≤ a, b≤ n)。保证没有自环和重边。保证图连通。
接下来一个整数q表示询问的个数(1≤ q≤ 100000)。
接下来q行每行两个整数a和b表示询问a和b之间的最短路。
题解:
这不是LCA的板子题吗?等等,m<n+100,那好像不是一棵树了???是一张图
仔细一看你会发现,m仅比n多一百个,也就是说会如果把这一百条边给挑出来,他还是一个LCA的模板题,所以这个题我们大体思路就是先把这一百条边给挑出来,然后对剩余的边进行LCA,然后对于剩下的边,我们再把它加进去,暴力跑100次bfs即可。
那么问题来了,我们怎么找这一百条边呢?
当然事并查集了,我们设想一下,在一棵树上,利用并查集,如果两个结点通过并查集发现,他们已经有一个共同的祖先,那么这条边不就是把两个孩子给连接起来了吗,这就是我们所说的那多余的边之一。找出这些边,先暂存与容器里,等跑完LCA后,再把点加进去暴力bfs更新。
代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 1e5+200;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;

const int imax=20;
struct node{
    int to,next;
}edge[maxn<<1];
int cnt=1,num;
int head[maxn<<1];
int deep[maxn];
bool visited[maxn];
int fa[maxn][imax+1];
int f[maxn];
int dis[110][maxn];
inline void add(int u,int v){
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
inline void dfs(int root,int father){
    //cout<<root<<endl;
    fa[root][0]=father;
    deep[root]=deep[father]+1;
    for(int i=1;(1<<i)<=deep[root];i++){
        fa[root][i]=fa[fa[root][i-1]][i-1];
    }
    for(int i=head[root];i;i=edge[i].next){
        if(edge[i].to==father) continue;
        dfs(edge[i].to,root);
    }
}
inline int lca(int x,int y){
    if(deep[x]>deep[y]) swap(x,y);
    for(int i=imax;i>=0;i--){
        if(fa[y][i]!=-1&&deep[fa[y][i]]>=deep[x]){
            y=fa[y][i];
        }
    }
    if(x==y) return x;
    for(int i=imax;i>=0;i--){
        if(fa[x][i]!=-1&&fa[y][i]!=-1&&fa[x][i]!=fa[y][i]){
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];
}

inline void bfs(int s){
    num++;
    dis[num][s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty()){
        int temp=q.front();
        q.pop();
        for(int i=head[temp];i;i=edge[i].next){
            if(dis[num][edge[i].to]>dis[num][temp]+1){
                dis[num][edge[i].to]=dis[num][temp]+1;
                q.push(edge[i].to);
            }
        }
    }
}

inline int ifind(int x){
    if(f[x]==x) return x;
    return f[x]=ifind(f[x]);
}
template<typename T>
inline T read(){
    T s=0,f=1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f=-1;ch = getchar();}
    while(isdigit(ch)) {s=(s<<3)+(s<<1)+ch-48;ch = getchar();}
    return s*f;
}
int main(){
    int n,m,k;
    memset(dis,MaxN,sizeof(dis));
    for(int i=0;i<maxn;i++){
        visited[i]=false;
        f[i]=i;
    }
    vector<pair<int,int> > v;
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int x,y;
        x=read<int>(),y=read<int>();
        int dx=ifind(x);
        int dy=ifind(y);
        if(dx==dy) v.push_back(make_pair(x,y));
        else{
            f[dx]=dy;
            add(x,y);
            add(y,x);
        }
    }
    dfs(1,0);
    for(auto it:v){
        add(it.first,it.second);
        add(it.second,it.first);
    }
    for(auto it : v){
        bfs(it.first);
    }
    int q;
    cin>>q;
    while (q--){
        int x,y;
        x=read<int>(),y=read<int>();
        int temp=lca(x,y);
        int ans=deep[x]+deep[y]-2*deep[temp];
        //cout<<ans<<endl;
        for(int i=1;i<=num;i++){
            ans=min(ans,dis[i][x]+dis[i][y]);
        }
        printf("%d\n",ans);
    }
    return  0;
}
题解 文章被收录于专栏

主要写一些题目的题解

全部评论

相关推荐

10-30 22:18
已编辑
毛坦厂中学 C++
点赞 评论 收藏
分享
10-17 12:16
同济大学 Java
7182oat:快快放弃了然后发给我,然后让我也泡他七天最后再拒掉,狠狠羞辱他一把😋
点赞 评论 收藏
分享
oppo 应用软开 22*15+0.5*12
拿到了ssp完美:真的坎坷,但是你至少拿到这么多offer了!
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务