Description
【故事の背景】
鸡腿君,CZYZ著名DS,江苏延陵人,天朝64年夏赴张江公学,遇学霸,遂溃逃。后至申城地铁,奈何不识路线,幸而得路人甲好心指路,乃至于邯郸路。
【问题の描述】
上海又叫做申城,那里的地铁一直是很拥挤的。鸡腿从张江去邯郸本部的路上常常是挤得……瘦了一圈。但是呢今天因为没有学霸的碾压,鸡腿心情很好决定要出去玩。为了避免遇上残酷的拥挤的地铁线,鸡腿想要查找一些路线中的必经地点,请你来告诉他吧。
上海的地铁被描述为N个点M条边的一个无向图,每次鸡腿会告诉你他在第S条路上,想要到第T条路上(别问我为什么是路上……),你能告诉他有多少个途中的点是他必须要经过的吗?
对于20%的数据1 ≤ N ≤ 10^2,1 ≤ M ≤ 10^3,1 ≤ Q ≤ 10^3;
对于40%的数据 1 ≤ N ≤ 10^3,1 ≤ M ≤ 10^4,1 ≤ Q ≤ 10^3;
对于100%的数据 1 ≤ N ≤ 10^4,1 ≤ M ≤ 10^5,1 ≤ Q ≤ 10^4,0
Solution
本弱第一题圆方树,从第一次听说到写题已经过去一个多月了
大概做法就是tarjan求点双,对于点双连成菊花图,这样图上的问题就能变成树上的问题了
把边当成点建图那么圆方树上两点间圆点数量即为答案
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define drp(i,st,ed) for (register int i=st;i>=ed;--i)
const int N=300005;
const int E=800005;
struct edge {int y,next;} e[E];
std:: stack <int> stack;
int dfn[N],low[N],dep[N],sum[N],fa[N][21];
int ls[N],ls1[N],edCnt=1,tot,n,m;
bool vis[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void add_edge1(int x,int y) {
e[++edCnt]=(edge) {y,ls1[x]}; ls1[x]=edCnt;
e[++edCnt]=(edge) {x,ls1[y]}; ls1[y]=edCnt;
}
void dfs1(int now,int from) {
dfn[now]=low[now]=++dfn[0]; vis[now]=1;
for (int i=ls[now];i;i=e[i].next) {
if ((i^1)==from) continue;
if (!dfn[e[i].y]) {
stack.push(i); dfs1(e[i].y,i);
low[now]=std:: min(low[now],low[e[i].y]);
if (low[e[i].y]>=dfn[now]) {
int y=0; ++ tot;
while (y!=i) {
y=stack.top(); stack.pop();
add_edge1(tot,e[y].y);
}
add_edge1(now,tot);
}
} else if (vis[e[i].y]) low[now]=std:: min(low[now],dfn[e[i].y]);
}
vis[now]=1;
}
void dfs2(int now) {
sum[now]+=(now<=n);
rep(i,1,20) fa[now][i]=fa[fa[now][i-1]][i-1];
for (int i=ls1[now];i;i=e[i].next) {
if (e[i].y==fa[now][0]) continue;
fa[e[i].y][0]=now; dep[e[i].y]=dep[now]+1;
sum[e[i].y]+=sum[now];
dfs2(e[i].y);
}
}
int get_lca(int x,int y) {
if (dep[x]<dep[y]) std:: swap(x,y);
drp(i,20,0) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if (x==y) return x;
drp(i,20,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(void) {
n=read(),m=read();
rep(i,1,m) {
int x=read(),y=read();
add_edge(x,i+n); add_edge(i+n,y);
} tot=n+m; dep[1]=1;
dfs1(1,-1);
dfs2(1);
for (int T=read();T--;) {
int x=read()+n,y=read()+n;
int lca=get_lca(x,y);
printf("%d\n", sum[x]+sum[y]-2*sum[lca]+(lca<=n));
}
return 0;
}