题意
一个无向图可以有重边,下面 个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(注意是要考虑之前连了的边,每次回答是在上一次的基础之上)
分析
求出桥来之后缩点,缩点运用并查集实现,每一个点组用父亲节点代表。emm,好像就这样。
PS:
虽说楼上大佬说并查集实现更快,但我还是比 慢啊。我太菜了/kk
代码
#include<bits/stdc++.h>
#define ll long long
const int N=2e5+5,INF=0x3f3f3f3f,mod=998244353;
using namespace std;
inline int read()
{
register int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
int tot,nxt[N*2],point[N],v[N*2],num,dfn[N],low[N],stack_[N],ss,nn;
int belong[N],f[N],father[N],ans;
bool vis[N];
void cl()
{
tot=0;memset(point,0,sizeof(point));
memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low));
nn=0;ss=0;num=0;ans=0;
}
void addline(int x,int y)
{
nxt[++tot]=point[x];point[x]=tot;v[tot]=y;
nxt[++tot]=point[y];point[y]=tot;v[tot]=x;
}
int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++nn;vis[x]=1;stack_[++ss]=x;
bool fff=0;
for (int i=point[x];i;i=nxt[i])
{
if (v[i]==fa && !fff){fff=1; continue;}
if (!dfn[v[i]])
{
father[v[i]]=x;
tarjan(v[i],x);
low[x]=min(low[x],low[v[i]]);
if (low[v[i]]>dfn[x]) ans++;
else f[find(v[i])]=find(x);
}
else low[x]=min(low[x],dfn[v[i]]);
}
}
int lca(int x,int y)
{
if (dfn[x]<dfn[y]) swap(x,y);
while (dfn[x]>dfn[y])
{
int xx=find(x),ff=find(father[x]);
if (xx!=ff) ans--,f[xx]=ff;
x=father[x];
}
while (y!=x)
{
int xx=find(y),ff=find(father[y]);
if (xx!=ff) ans--,f[xx]=ff;
y=father[y];
}
return ans;
}
int main()
{
int cnt=0,n,m,i,q;
n=read();m=read();
while(n&&m)
{
cl();int x,y;
for (i=1;i<=m;i++)
{
x=read();y=read();
addline(x,y);
}
for (i=1;i<=n;i++) f[i]=i;
tarjan(1,0);
q=read();
printf("Case %d:\n",++cnt);
for (i=1;i<=q;i++)
{
x=read();y=read();
printf("%d\n",lca(x,y));
}
printf("\n");
n=read();m=read();
}
}
京公网安备 11010502036488号