传送门
点双连通分量等价于去掉任意一个点仍然连通。那么任意两个点都同时包含在一个简单环中。
边双连通分量等价于任意一条边都在一个简单环上。
求出点双判断一下点数是否等于边数。
#include<bits/stdc++.h>
#define re register
#define cs const
cs int N=1e6+10;
namespace IO{
cs int Rlen=1<<22|1;
char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
template<typename T>
inline T get(){
char ch;T x;
while(!isdigit(ch=gc()));x=ch^48;
while(isdigit(ch=gc())) x=((x+(x<<2))<<1)+(ch^48);
return x;
}
inline int gi(){return get<int>();}
}
using namespace IO;
int n,m,s[N],t[N],I[N<<1];
int Head[N],Next[N<<1],V[N<<1],cnt=0;
int low[N],dfn[N],st[N],belong[N],top=0,tot=0;
int bcc_pnt[N],bcc_siz[N],bcc_val[N],bcc_cnt=0;
inline void add(int u,int v,int id){Next[++cnt]=Head[u],V[cnt]=v,I[cnt]=id,Head[u]=cnt;}
inline void tarjan(int u,int f){
dfn[u]=low[u]=++tot;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]]) if(v!=f){
if(!dfn[v]){
st[++top]=I[i],tarjan(v,u);
low[u]=std::min(low[u],low[v]);
if(low[v]>=dfn[u]){
++bcc_cnt;
while(1){
int now=st[top--];++bcc_siz[bcc_cnt],bcc_val[bcc_cnt]^=now;
if(belong[s[now]]!=bcc_cnt) ++bcc_pnt[bcc_cnt],belong[s[now]]=bcc_cnt;
if(belong[t[now]]!=bcc_cnt) ++bcc_pnt[bcc_cnt],belong[t[now]]=bcc_cnt;
if((s[now]==u&&t[now]==v)||(s[now]==v&&t[now]==u))
break;
}
}
}
else low[u]=std::min(low[u],dfn[v]),st[++top]=I[i];
}
}
int ans=0;
int main(){
// freopen("graph.in","r",stdin);
// freopen("graph.out","w",stdout);
n=gi(),m=gi();
for(int re i=1,u,v;i<=m;++i)
s[i]=(u=gi()),t[i]=(v=gi()),add(u,v,i),add(v,u,i);
tarjan(1,0);
for(int i=1;i<=bcc_cnt;++i)
if(bcc_pnt[i]==bcc_siz[i]) ans^=bcc_val[i];
printf("%d\n",ans);
}
1207

被折叠的 条评论
为什么被折叠?



