BZOJ4424: Cf19E Fairy

BZOJ4424: Cf19E Fairy

CF19E. Fairy

Description

给定 n 个点,m 条边的无向图,可以从图中删除一条边,问删除哪些边可以使图变成
一个二分图。

Input

第 1 行包含两个整数 n,m。分别表示点数和边数。
第 2 到 m+1 行每行两个数 x,y 表示有一条(x,y)的边。

Output

输出第一行一个整数,表示能删除的边的个数。
接下来一行按照从小到大的顺序输出边的序号。

Sample Input

4 4
1 2
1 3
2 4
3 4

Sample Output

4
1 2 3 4

HINT

100%的数据,n,m<=1000000


题解Here!

感觉和某个题好像啊:

BZOJ4025: 二分图

一个图是二分图当且仅当它没有奇环。
然后如果一个图已经是二分图,那么删除任意一条边都还是二分图。
于是我们考虑随便求出一棵生成树。
然后把非树边都拿出来,求出它们两个点的$LCA$和距离$dis$。
这样,我们可以尝试一条条把非树边放在树上,看是否会构成奇环,统计奇环条数$flag$。
以下将构成奇环的非树边叫做矛盾边,不会构成奇环的非树边叫做合法边。
一条树上边被非树上边$(u,v)$“覆盖”,即这条树上边在$u->v$的树上路径上。
然后分类讨论:
  • 如果$flag==0$,即没有奇环。

只要把所有边序号输出即可

  • 如果$flag==1$,即有一个奇环。

那么我们的一个选择是把该条矛盾边删掉,或者是在该矛盾边$(u,v)$的树上路径上找一些边,满足这些边不被合法边覆盖。

至于为什么要让其不被合法边覆盖,画个图感性理解一下。。。

这样可以保证该矛盾边不会与其他非矛盾边再形成奇环。

  • 如果$flag>1$,即有若干个奇环。

那么我们只能选择删除树上那些,被所有矛盾边覆盖,且不被非矛盾边覆盖的边了。

但是如何判断呢?

我们可以利用树上差分的思想,记$delta[x]$为$x$和其父亲构成的边上的差分值,把矛盾边的路径$+1$,非矛盾边的路径上$-1$。

那么最后树上的点$x$如果满足$delta[x]==flag$,那么它与它的父亲组成的边就是我们所求的。

注意:图有可能不连通,并且会有重边与自环!

我考虑了这些,但是在$BZOJ$上光荣$WA$了。。。

我不服,“上诉”到$codeforces$,然后$AC$。。。

所以$BZOJ$上的是个什么鬼数据啊。。。我交了几个网上的题解好像还有没过的。。。

所以这个题就这样吧,有时间再来改。。。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 1000010
using namespace std;
int n,m,c=1,d=0,e=1,flag=0;
int start,end,ancester,id;
int head[MAXN],h[MAXN],deep[MAXN],fa[MAXN],father[MAXN],vis[MAXN],delta[MAXN];
int last[MAXN],ans[MAXN];
struct Edge{
	int x,y;
}edge[MAXN];
struct Tree{
	int next,to,id;
}tree[MAXN<<1],question[MAXN<<1];
struct Question{
	int x,y,id,lca;
}que[MAXN];
inline int read(){
	int date=0;char c=0;
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date;
}
int find(int x){return father[x]==x?x:father[x]=find(father[x]);}
void uniun(int x,int y){x=find(x);y=find(y);if(x!=y)father[y]=x;}
inline void add(int x,int y,int i){
	tree[c].to=y;tree[c].id=i;tree[c].next=head[x];head[x]=c++;
	tree[c].to=x;tree[c].id=i;tree[c].next=head[y];head[y]=c++;
}
inline void add_que(int x,int y,int i){
	question[e].to=y;question[e].id=i;question[e].next=h[x];h[x]=e++;
	question[e].to=x;question[e].id=i;question[e].next=h[y];h[y]=e++;
}
void kruskal(){
	for(int i=1;i<=n;i++)father[i]=i;
	for(int i=1;i<=m;i++){
		if(find(edge[i].x)!=find(edge[i].y)){
			uniun(edge[i].x,edge[i].y);
			add(edge[i].x,edge[i].y,i);
		}
		else{
			d++;
			que[d]=(Question){edge[i].x,edge[i].y,i,0};
			add_que(edge[i].x,edge[i].y,d);
		}
	}
}
void LCA(int x){
	vis[x]=1;
	for(int i=head[x];i;i=tree[i].next){
		int v=tree[i].to;
		if(!vis[v]){
			deep[v]=deep[x]+1;
			fa[v]=x;
			last[v]=tree[i].id;
			LCA(v);
			uniun(x,v);
		}
	}
	for(int i=h[x];i;i=question[i].next){
		int v=question[i].to;
		if(father[v])que[question[i].id].lca=find(v);
	}
}
void get_sum(int x){
	int v;
	for(int i=head[x];i;i=tree[i].next){
		v=tree[i].to;
		if(!vis[v]){
			vis[v]=1;
			get_sum(v);
			delta[x]+=delta[v];
		}
	}
}
void work(){
	if(!flag){
		printf("%d
",m);
		for(int i=1;i<=m;i++)printf("%d ",i);
		printf("
");
	}
	else if(flag==1){
		int top=0;
		for(int i=start;i!=ancester;i=fa[i])if(delta[i]==1)ans[++top]=last[i];
		for(int i=end;i!=ancester;i=fa[i])if(delta[i]==1)ans[++top]=last[i];
		ans[++top]=id;
		sort(ans+1,ans+top+1);
		printf("%d
",top);
		for(int i=1;i<=top;i++)printf("%d ",ans[i]);
		printf("
");
	}
	else{
		int top=0;
		for(int i=1;i<=n;i++)if(delta[i]==flag)ans[++top]=last[i];
		sort(ans+1,ans+top+1);
		printf("%d
",top);
		for(int i=1;i<=top;i++)printf("%d ",ans[i]);
		printf("
");
	}
}
void init(){
	int x,y,lca,dis,v;
	n=read();m=read();
	for(int i=1;i<=m;i++){edge[i].x=read();edge[i].y=read();}
	kruskal();
	for(int i=1;i<=n;i++)father[i]=i;
	for(int i=1;i<=n;i++)if(!vis[i]){deep[i]=1;LCA(i);}
	for(int i=1;i<=d;i++){
		x=que[i].x;y=que[i].y;lca=que[i].lca;v=1;
		dis=deep[x]+deep[y]-2*deep[lca];
		if(dis&1)v=-1;
		else{
			flag++;
			start=x;end=y;ancester=lca;id=que[i].id;
		}
		delta[x]+=v;delta[y]+=v;delta[lca]-=2*v;
	}
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)if(!vis[i]){vis[i]=1;get_sum(i);}
}
int main(){
	init();
	work();
    return 0;
}
原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9926069.html