AcWing397 逃不掉的路(边双)
无向图缩点的low值定义是经过一条B边能够到的点的dfn的最小值
如果low[v]>=low[u],说明有割点,但是要特判树边,如果low[v]>low[u],说明是有割边,但是要特判重边,本题很显然边双里的点都是不必要的
只有桥是必要的,先缩点之后跑一下lca
#include<bits/stdc++.h> using namespace std; const int N=5e5+10; int h[N],ne[N],idx,e[N],cnt; int dfn[N],low[N],isce[N]; int f[N][21]; int ecc[N]; int depth[N]; int fa[N]; vector<int> g[N]; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int n,m,times,ans; void tarjan(int u){ dfn[u]=low[u]=++times; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(!dfn[j]){ fa[j]=u; tarjan(j); low[u]=min(low[u],low[j]); if(dfn[u]<low[j]) isce[j]=1; } else if(j!=fa[u]) low[u]=min(low[u],dfn[j]); } } void dfs(int u,int x){ ecc[u]=x; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(ecc[j]||fa[j]==u&&isce[j]||fa[u]==j&&isce[u]) continue; dfs(j,x); } } void bfs(){ queue<int> q; q.push(1); memset(depth,0x3f,sizeof depth); depth[0]=0,depth[1]=1; while(q.size()){ int t=q.front(); q.pop(); int i; for(i=0;i<(int)g[t].size();i++){ int j=g[t][i]; if(depth[j]>depth[t]+1){ depth[j]=depth[t]+1; q.push(j); f[j][0]=t; for(int k=1;k<=20;k++){ f[j][k]=f[f[j][k-1]][k-1]; } } } } } int lca(int a,int b){ if(depth[a]<depth[b]) swap(a,b); int i; for(i=20;i>=0;i--){ if(depth[f[a][i]]>=depth[b]){ a=f[a][i]; } } if(a==b) return a; for(i=20;i>=0;i--){ if(f[a][i]!=f[b][i]){ a=f[a][i]; b=f[b][i]; } } return f[a][0]; } int main(){ ios::sync_with_stdio(false); cin>>n>>m; int i; memset(h,-1,sizeof h); for(i=1;i<=m;i++){ int a,b; cin>>a>>b; add(a,b); add(b,a); } tarjan(1); for(i=1;i<=n;i++){ if(!ecc[i]){ dfs(i,++cnt); } } for(i=1;i<=n;i++){ int j; for(j=h[i];j!=-1;j=ne[j]){ int k=e[j]; if(ecc[i]==ecc[k]) continue; g[ecc[i]].push_back(ecc[k]); } } bfs(); int qi; cin>>qi; while(qi--){ int x,y; cin>>x>>y; x=ecc[x],y=ecc[y]; int p=lca(x,y); cout<<depth[x]+depth[y]-2*depth[p]<<endl; } }
没有人不辛苦,只有人不喊疼