CodeForces1046B Hyperspace Highways

传送门

题意:
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]);
	}
}

你可能感兴趣的:(懵逼了半天终于AC)