题意:给一个图,问删除哪些边可以让原图变为二分图
继续旧题补档,这题当时打比赛加强到了$2000000$
一个图是二分图当且仅当它不含奇环,所以我们要做的就是删边以破坏奇环
对图dfs,得到dfs树,此时非树边只会是返祖边,返祖边+树上路径可以构成环,我们把这种环称为“简单环”
如果没有简单奇环,那么它本来就是二分图,删掉任意一条边还是二分图
如果只有$1$个简单奇环,那么构成这个简单奇环的返祖边是可以删的
一条树边能删当且仅当所有奇环经过它而且没有偶环经过它,因为既要破坏所有奇环又不能构成新的奇环
统计奇环偶环直接dfs时差分统计即可
#include<stdio.h>
#include<algorithm>
using namespace std;
int h[2000010],to[4000010],nex[4000010],fa[2000010],dep[2000010],fae[2000010],d1[2000010],d2[2000010],s1[2000010],s2[2000010],ans[2000010],cnt,o,e,n,m,o1;
void add(int a,int b,int i){
to[i]=b;
nex[i]=h[a];
h[a]=i;
i+=m;
to[i]=a;
nex[i]=h[b];
h[b]=i;
}
int down(int x){
if(x>m)x-=m;
return x;
}
void dfs(int x){
for(int i=h[x];i;i=nex[i]){
if(dep[to[i]]==0){
dep[to[i]]=dep[x]+1;
fa[to[i]]=x;
fae[to[i]]=down(i);
dfs(to[i]);
s1[x]+=s1[to[i]];
s2[x]+=s2[to[i]];
}else if(to[i]!=fa[x]&&dep[x]>dep[to[i]]){
if((dep[x]-dep[to[i]])&1){
e++;
d2[x]++;
d2[to[i]]--;
}else{
o++;
d1[x]++;
d1[to[i]]--;
o1=down(i);
}
}
}
s1[x]+=d1[x];
s2[x]+=d2[x];
}
int rev(int x){
if(x>m)return x-m;
return x+m;
}
int gao(int x){
if(fa[to[x]]==to[rev(x)])return to[x];
if(fa[to[rev(x)]]==to[x])return to[rev(x)];
return 0;
}
int main(){
int i,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y,i);
}
for(i=1;i<=n;i++){
if(dep[i]==0){
dep[i]=1;
dfs(i);
}
}
if(o==0){
printf("%d\n",m);
for(i=1;i<=m;i++)printf("%d ",i);
return 0;
}
if(o==1){
cnt=1;
ans[1]=o1;
}
for(i=1;i<=m;i++){
x=gao(i);
if(x){
if(s1[x]==o&&s2[x]==0){
cnt++;
ans[cnt]=i;
}
}
}
printf("%d\n",cnt);
sort(ans+1,ans+cnt+1);
for(i=1;i<=cnt;i++)printf("%d ",ans[i]);
}