有这样一个显然的结论:在同一个边双中的点没有必经边(因为至少有两条分离的路径)
由此可得,两点之间的必经边就是它们之间的桥的数量.
那么,先将所有e-DCC缩点,得到一棵树,问题转化为求这个树上任意两点间的树上距离.树剖LCA绝杀.
时间复杂度$O(n+m+Qlogn)$
/**********/省略快读
#define MAXM 200011
struct Graph
{
struct Edge
{
ll v,nxt;
}e[MAXM<<1|1];
ll last[MAXM],cnt;
Graph()
{
cnt=1;
}
void adde(ll u,ll v)
{
e[++cnt].v=v;
e[cnt].nxt=last[u],last[u]=cnt;
}
}e,se;
ll dfn[MAXM],low[MAXM],deg[MAXM],cur=0;
ll ecc[MAXM],ecnt=0;
bool bridge[MAXM];
void tarjan(ll u,ll in_edge=0)//tarjan缩点
{
dfn[u]=low[u]=++cur;
for(ll i=e.last[u];i;i=e.e[i].nxt)
{
if(i==(in_edge^1))continue;
ll v=e.e[i].v;
if(!dfn[v])
{
tarjan(v,i);
umin(low[u],low[v]);
if(low[v]>dfn[u])bridge[i]=bridge[i^1]=1;
}
else umin(low[u],dfn[v]);
}
}
void dfs(ll u,ll in_edge=0)
{
ecc[u]=ecnt;
for(ll i=e.last[u];i;i=e.e[i].nxt)
{
if(i==(in_edge^1)||bridge[i])continue;
ll v=e.e[i].v;
if(!ecc[v])dfs(v,i);
}
}
ll size[MAXM],fa[MAXM],mson[MAXM],dep[MAXM];//树剖LCA
void dfs1(ll u,ll now=1)
{
size[u]=1;
dep[u]=now;
for(ll i=se.last[u];i;i=se.e[i].nxt)
{
ll v=se.e[i].v;
if(v==fa[u])continue;
fa[v]=u,dep[v]=dep[u]+1;
dfs1(v,now+1);
size[u]+=size[v];
if(size[v]>size[mson[u]])mson[u]=v;
}
}
ll top[MAXM];
void dfs2(ll u,ll cur)
{
top[u]=cur;
if(mson[u])dfs2(mson[u],cur);
for(ll i=se.last[u];i;i=se.e[i].nxt)
{
ll v=se.e[i].v;
if(v==fa[u]||v==mson[u])continue;
dfs2(v,v);
}
}
ll LCA(ll u,ll v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>=dep[top[v]])
{
u=fa[top[u]];
}
else v=fa[top[v]];
}
if(dep[u]>=dep[v])return v;
else return u;
}
ll dist(ll u,ll v)
{
return dep[u]+dep[v]-2*dep[LCA(u,v)];
}
int main()
{
ll n=read(),m=read();
for(ll i=1;i<=m;++i)
{
ll u=read(),v=read();
e.adde(u,v),e.adde(v,u);
}
tarjan(1);
for(ll i=1;i<=n;++i)
if(!ecc[i])++ecnt,dfs(i);
//for(ll i=1;i<=n;++i)printf("ecc[%lld]=%lld\n",i,ecc[i]);
for(ll u=1;u<=n;++u)
for(ll i=e.last[u];i;i=e.e[i].nxt)
{
ll v=e.e[i].v;
if(ecc[u]!=ecc[v])se.adde(ecc[u],ecc[v]);
}
dfs1(1,1);dfs2(1,1);
ll q=read();
for(ll i=1;i<=q;++i)
{
ll u=read(),v=read();
printf("%lld\n",dist(ecc[u],ecc[v]));
}
return 0;
}
伪代码QAQ