传送门
题意:
N个点,M条边,每一个环上的点两两有边相连。q次询问两点间最短距离。
题解:
构造圆方树,那么两点间距离感性认知一下就可以发现是树上两点间距离的一半。然后
dist(u,v)=(dep[u]+dep[v]-2*dep[lca])/2即可。
继续存板子。
代码:
#include
#include
#define maxn 200005
#define maxm 1400005
using namespace std;
int n,m,q,n1,a[maxn],head1[maxn],head2[maxn],ncnt,dfn[maxn],low[maxn],ccnt,stk[maxn],tp;
int siz[maxn],tid[maxn],rnk[maxn],fa[maxn],dep[maxn],son[maxn],top[maxn];
struct node { int v,nxt; } e[maxm];
void addedge(int head[],int u,int v)
{
ncnt++;
e[ncnt].v=v,e[ncnt].nxt=head[u];
head[u]=ncnt;
}
void dfs(int u,int fa)
{
dfn[u]=low[u]=++ccnt; stk[++tp]=u;
for(int p=head1[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(!dfn[v])
{
dfs(v,u); low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
addedge(head2,u,++n1); addedge(head2,n1,u);
do { addedge(head2,stk[tp],n1); addedge(head2,n1,stk[tp]); } while(stk[tp--]!=v);
}
}
else if(v!=fa) low[u]=min(low[u],dfn[v]);
}
}
void dfs1(int u,int f)
{
fa[u]=f,siz[u]=1,dep[u]=dep[f]+1;
for(int p=head2[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(v==f) continue;
dfs1(v,u); siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp,tid[u]=++ccnt,rnk[ccnt]=u;
if(!son[u]) return;
dfs2(son[u],tp);
for(int p=head2[u];p;p=e[p].nxt)
{
int v=e[p].v;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
int lca(int u,int v)
{
while(top[u]!=top[v])
if(dep[top[u]]<dep[top[v]]) v=fa[top[v]];
else u=fa[top[u]];
return dep[u]<dep[v]?u:v;
}
int main()
{
scanf("%d%d%d",&n,&m,&q); n1=n;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(head1,u,v); addedge(head1,v,u);
}
dfs(1,0); ccnt=0;
dfs1(1,0); dfs2(1,1);
while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
int lc=lca(u,v);
printf("%d\n",(dep[u]+dep[v])/2-dep[lc]);
}
}