【题解】道路相遇

道路相遇

( ext{Solution:})

题意就是对于 ((u,v)) 找有多少个必经点。

必经边就很简单了,直接上边双缩点。这里我们用圆方树解决必经点问题。

考虑到圆方树的性质:方点和圆点一定是相邻的,没有一个圆点连圆点,也没有一个方点连方点。

而对于两点的必经点,就是这条路径上的割点个数,也就是方点个数。

那方点个数不就恰好是路径长度除以 (2)(-1) 吗,然后加上题目要求的原来的两个点就完成了。

注意这题卡常:一个是空间开大,一个是在 tarjan 的时候就进行建图,避免使用 vector ,还有注意空间别开小,这里提示空间开小导致了 MLE.

还有,链一类的东西也是有圆方树的,每相邻两个点构成点双,并且除了度为 (1) 的节点都是割点,它们可以满足圆方相邻的树结构。

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int head[N],Head[N],tot,tto,n,m;
struct E{int nxt,to;}e[N],edge[N<<1];
inline void link(int x,int y,int w=0){
	if(w){
		edge[++tto]=(E){Head[x],y};
		Head[x]=tto;
		return;
	}
	e[++tot]=(E){head[x],y};
	head[x]=tot;
}
int dfn[N],low[N],dfstime,top,st[N],dep[N],Q;
int node,siz[N],son[N],ttop[N],pa[N];
void dfs1(int x,int fa){
	siz[x]=1;pa[x]=fa;
	dep[x]=dep[fa]+1;
	for(int i=Head[x];i;i=edge[i].nxt){
		int j=edge[i].to;
		if(j==fa)continue;
		dfs1(j,x);
		siz[x]+=siz[j];
		if(siz[j]>siz[son[x]])son[x]=j;
	}
}
void dfs2(int u,int t){
	ttop[u]=t;
	if(!son[u])return;
	dfs2(son[u],t);
	for(int i=Head[u];i;i=edge[i].nxt){
		int j=edge[i].to;
		if(j==son[u]||j==pa[u])continue;
		dfs2(j,j);
	}
}
inline void write(int x){
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline int Min(int x,int y){return x<y?x:y;}
void tarjan(int x,int root){
	st[++top]=x;
	low[x]=dfn[x]=++dfstime;
	if(x==root&&!head[x]){
		++node;
		link(x,node,1);
		link(node,x,1);
		return;
	}
	int ch=0;
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(!dfn[j]){
			ch++;
			tarjan(j,root);
			low[x]=Min(low[x],low[j]);
			if(low[j]>=dfn[x]){
				int vex=-1;
				++node;
				do{
					vex=st[top--];
					link(node,vex,1);
					link(vex,node,1);
				}while(vex!=j);
				link(node,x,1);
				link(x,node,1);
			}
		}
		else low[x]=Min(low[x],dfn[j]);
	}
}
int LCA(int x,int y){
	while(ttop[x]!=ttop[y]){
		if(dep[ttop[x]]<dep[ttop[y]])swap(x,y);
		x=pa[ttop[x]];
	}
	return dep[x]<dep[y]?x:y;
}
inline int read(){
	int s=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch)){
		s=s*10-'0'+ch;
		ch=getchar();
	}
	return s;
}
int main(){
	n=read();m=read();
	for(int i=1;i<=m;++i){
		int x=read(),y=read();
		link(x,y);link(y,x);
	}
	node=n;
	for(int i=1;i<=n;++i)if(!dfn[i])top=0,tarjan(i,i);
	for(int i=1;i<=node;++i){
		if(!dep[i]){
			dfs1(i,0);
			dfs2(i,i);
		}
	}
	Q=read();
	while(Q--){
		int u=read(),v=read();
		int L=LCA(u,v);
		write((dep[u]+dep[v]-dep[L]-dep[L])/2+1);
		putchar('
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/h-lka/p/15312212.html