[CF19E]Fairy

Posted jefflyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF19E]Fairy相关的知识,希望对你有一定的参考价值。

题意:给一个图,问删除哪些边可以让原图变为二分图

继续旧题补档,这题当时打比赛加强到了$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]);
}

以上是关于[CF19E]Fairy的主要内容,如果未能解决你的问题,请参考以下文章

[CF19E]Fairy

CF 19E Fairy——树上差分

BZOJ4424Cf19E Fairy DFS树

bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy树形dp

bzoj千题计划229:bzoj4424: Cf19E Fairy

CF19 E Fairy——树上差分