题解 P4320 【道路相遇】
大家观察一张图
有什么发现?
必经点数==圆方树上两点路径上圆点数
也就等于边数/2+1
于是对图建出广义圆方树(怎么建?
然后树剖求
亲测树剖时间是倍增一半
#define il inline
#define ri register int
#include<iostream>
using namespace std;
const int N=1e6+5,M=4e6+5;
il int re(){
ri x=0,w=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
int n,E,m,ts,tp,tot;
int dfn[N],low[N],st[N],dep[N],top[N],sz[N],son[N],fa[N];
struct Graph{
int cnt,last[N],nxt[M],to[M];
il void link(ri u,ri v){
nxt[++cnt]=last[u];to[cnt]=v;last[u]=cnt;
nxt[++cnt]=last[v];to[cnt]=u;last[v]=cnt;
}
}G,T;
void tarjan(ri u){
dfn[u]=low[u]=++ts;st[++tp]=u;
for(ri i=G.last[u],v;i;i=G.nxt[i]){
v=G.to[i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
T.link(++tot,u);
ri x=0;
do{
x=st[tp--];T.link(tot,x);
}while(x!=v);
}
}
else low[u]=min(low[u],dfn[v]);
}
}
void dfs1(ri u){
sz[u]=1;
for(ri i=T.last[u],v;i;i=T.nxt[i]){
v=T.to[i];
if(v==fa[u])continue;
dep[v]=dep[u]+1;
fa[v]=u;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(ri u,ri Tp){
top[u]=Tp;
if(son[u])dfs2(son[u],Tp);
for(ri i=T.last[u],v;i;i=T.nxt[i]){
v=T.to[i];
if(v==son[u]||v==fa[u])continue;
dfs2(v,v);
}
}
il int Query(ri x,ri y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int main(){
tot=n=re(),E=re();
for(ri i=1,u,v;i<=E;i++){
u=re(),v=re();
G.link(u,v);
}
tarjan(1);
dep[1]=1;dfs1(1);dfs2(1,1);
m=re();
ri u,v,lca;
while(m--){
u=re(),v=re();
lca=Query(u,v);
printf("%d\n",(dep[u]+dep[v]-2*dep[lca])/2+1);
}
return 0;
}