最短路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; }
题解 文章被收录于专栏
主要写一些题目的题解