水60分
需要用到
一个叫桥的东西
这个桥是什么呢?
就是一条很重要的边,你把这条边去掉之后整个图就不连通了
接下来就可以发现,一张图的桥将这张图分成了一棵树
这棵树上的节点对应的是一个一个连通块
每一个连通块内的点到另一个连通块内的点之间的关键路径的条数
即为两个点之间桥的个数,也即为两个连通块在树上的路径
那么我们可以将原问题转化成求用桥构成的树上两点之间的距离了
那么
怎么求桥呢?怎么将原图用桥分开呢?
我们对原图进行一次dfs,在这过程中记录两个东西
dfn[i]:表示i的dfs序,即在dfs过程中被遍历到的顺序
low[i]:表示i能够连接到的最小的祖先,即i能够到达的已经被dfs过的dfs序最小的点
桥的判定:
如果对于一条边(u,v)
有 low[u]<dfn[v] 的话,那么这条边就为图上的一座桥
有了这个性质可以在dfs过程中求出桥了
求出桥之后,再考虑构建树边
如果把所有的桥全部拿走的话
可以看见整个图被分成了互不相连的好几个连通块
可以把这些连通块缩成树上的一个点
然后再把桥边放回去,构成树边
建完树之后就可以利用树上lca的知识来求树上两点之间的距离了
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cctype>
using namespace std;
const int MAXN=3e4+2,MAXE=1e5+2,S=20;
inline void Rd(int &res){
char c;res=0;
while(c=getchar(),!isdigit(c));
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),isdigit(c));
}
struct Edge{
int to,nxt;
}edge[MAXE];
int n,m,Q;
int head[MAXN],tot;
int e[MAXN][2];
int belongto[MAXN];
int isbridge[MAXN];
int dfn[MAXN],low[MAXN],T,bcnt;
vector<int>tree[MAXN];
int fa[MAXN][S],dep[MAXN];
inline void add(int a,int b){
edge[tot].to=b;edge[tot].nxt=head[a];head[a]=tot++;
}
void dfs(int x,int f){
dfn[x]=low[x]=++T;
for(int i=head[x];~i;i=edge[i].nxt){
int y=edge[i].to;
if(y==f)continue;
if(dfn[y]==0){
dfs(y,x);
if(low[y]>dfn[x])isbridge[i]=1,isbridge[i^1]=1;
else low[x]=min(low[x],low[y]);
}else low[x]=min(low[x],dfn[y]);
}
}
void setID(int x){
belongto[x]=bcnt;
for(int i=head[x];~i;i=edge[i].nxt){
if(isbridge[i]||belongto[edge[i].to])continue;
setID(edge[i].to);
}
}
void Tdfs(int now,int pre,int Dep){
fa[now][0]=pre;dep[now]=Dep;
for(int i=0;i<tree[now].size();i++){
int nxt=tree[now][i];
if(nxt==pre)continue;
Tdfs(nxt,now,Dep+1);
}
}
inline void init(){
for(int j=1;(1<<j)<n;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
inline void up(int &a,int step){
for(int i=0;i<S;i++)
if(step&(1<<i))
a=fa[a][i];
}
int LCA(int a,int b){
if(dep[a]>dep[b])swap(a,b);
up(b,dep[b]-dep[a]);
if(a!=b){
for(int i=S-1;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
a=fa[a][0];
}return a;
}
int main(){
memset(head,-1,sizeof(head));tot=0;
Rd(n),Rd(m),Rd(Q);
int a,b,type;
for(int i=0;i<m;i++){
Rd(a),Rd(b);
add(a,b);add(b,a);
e[i][0]=a;e[i][1]=b;
}
dfs(1,0);
for(int i=1;i<=n;i++)
if(!belongto[i]){
bcnt++;
setID(i);
}
for(int i=0;i<m;i++){
int a=belongto[e[i][0]],b=belongto[e[i][1]];
if(a==b)continue;
tree[a].push_back(b);
tree[b].push_back(a);
}
Tdfs(1,0,1);
init();
while(Q--){
Rd(type),Rd(a),Rd(b);
a=belongto[a];b=belongto[b];
int lca=LCA(a,b);
printf("%d\n",dep[a]+dep[b]-2*dep[lca]);
}
return 0;
}