每日一题 7月7日 最短路 01最短路+树的LCA

题目链接:https://ac.nowcoder.com/acm/problem/19814
题目大意:
图片说明
思路:
m最大为n+100,并且连通。我们可以假设开始一棵树。有q个查询u-v的最短路。然后添加了100条边。那么最短路可以发生变化的一定经过了这些边。假设这些边为x-y。那么经过了x点。我们以x为起点跑一个最短路,那么a-b的最短路可能为ans[i]=min(ans[i], dis[a]+dis[b])。当然对于每个查询我们不能去枚举一次100条边。而是用100条边上的点跑完最短路都去更新下q个查询。复杂度O(100qlogn)

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

struct node{
    int x;
    int y;
    int i;
}ans[1000050];
vector<node> G[1000050];
int vis[1000050], visE[1000050], ds[1000050], pw[1000050]={1};
struct LCA{
    int d[1000050], fa[1000050][22], lg[1000050];
    void init(int n, int root){//预处理
        for(int i = 1; i <= n; ++i){
            lg[i] = lg[i-1] + (1 << lg[i-1] == i);
        }
        dfs(root, 0);
    }
    void dfs(int now, int father){
        vis[now]=1;
        ds[now]=ds[father]+1;
        fa[now][0]=father; d[now]=d[father]+1;
        for(int i=1; i<=lg[d[now]]; ++i){
            fa[now][i]=fa[fa[now][i-1]][i-1];
        }
        for(auto x: G[now]){
            if(x.x!=father&&!vis[x.x]){
                visE[x.i]=1;
                dfs(x.x, now);
            }
        }
    }
    int lca(int x, int y){//LCA
        if(d[x]<d[y]) swap(x, y);
        while(d[x]>d[y]){
            x=fa[x][lg[d[x]-d[y]]-1];
        }
        if(x==y) return x;
        for(int k=lg[d[x]]-1; k>=0; --k){
            if(fa[x][k]!=fa[y][k]){
                x=fa[x][k], y=fa[y][k];
            }
        }
        return fa[x][0];
    }

}lca;

queue<int> q;
int dis[1000050];
void bfs(int u, int Q){
    memset(dis, -1, sizeof(dis));
    q.push(u), dis[u]=0;
    while(!q.empty()){//跑一次最短路
        int to=q.front(); q.pop();
        for(auto x: G[to]){
            if(dis[x.x]==-1){
                dis[x.x]=dis[to]+1;
                q.push(x.x);
            }
        }
    }
    for(int i=1; i<=Q; i++){//更新每个查询
        ans[i].i=min(ans[i].i, dis[ans[i].x]+dis[ans[i].y]);
    }
}

int form[1000050], to[1000050];
int main(){

    for(int i=1; i<=30; i++){
        pw[i]=pw[i-1]*2;
    }
    int n, m, x, y; scanf("%d%d", &n, &m);
    for(int i=1; i<=m; i++){
        scanf("%d%d", &x, &y);
        form[i]=x, to[i]=y;
        G[x].push_back(node{y,0, i});
        G[y].push_back(node{x,0, i});
    }
    lca.init(n+3, 1);//从图中得到一颗树
    int q; scanf("%d", &q);
    for(int i=1; i<=q; i++){
        scanf("%d%d", &x, &y);
        ans[i]=node{x, y, ds[x]+ds[y]-2*ds[lca.lca(x, y)]};
    }
    for(int i=1; i<=m; i++){
        if(!visE[i]){//非树边
            bfs(form[i], q);
        }
    }
    for(int i=1; i<=q; i++){
        printf("%d\n", ans[i].i);
    }

    return 0;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务