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