1. 程式人生 > >Newcoder 40 C.珂朵莉的二分圖(dfs+樹形)

Newcoder 40 C.珂朵莉的二分圖(dfs+樹形)

Description

珂朵莉給你一個無向圖

其有nn個點,mm條邊

對於每條邊,她想知道刪了這條邊之後這個圖是不是一個二分圖

Input

第一行兩個整數n,mn,m

之後mm行,每行兩個數x,yx,y表示有一條xxyy之間的無向邊

ii個邊的序號即為ii

(n,m106)(n,m\le 10^6)

output

第一行輸出一個整數,表示有多少邊滿足條件

接下來一行,從小到大輸出這些邊的序號

如果沒有邊滿足條件,只輸出一行一個數00,注意不要多輸出換行

Sample Input

4 4 1 2 1 3 2 4 3 4

Sample Output

4 1 2 3 4

Solution

一個圖是二分圖當且僅當該圖無奇環,若想讓該圖成為一個二分圖,必須破掉所有奇環,那麼就要選擇所有奇環交集中的一條邊,注意到一個奇環和一個偶環在刪去一條公共邊後依舊是一個奇環,故不能刪去偶環上的邊

具體做法,首先統計所有自環,如果又有奇環又有自環,顯然不行;如果沒有奇環但是有超過一個自環也不行;如果沒有自環也沒有奇環,刪去任意一條邊都行;如果沒有自環只有奇環,dfsdfs整張圖,維護每個點的深度,如果當前點uu的一個鄰接點vv之前被經過,且深度不超過uu(如果深度超過uu只能是有重邊,這種偶環不用管,因為這種邊不會出現在奇環的交集中),那麼說明u,vu,v之間構成一個環,且該環是由樹上的u

,vu,v這條鏈和當前的uvuv邊構成,我們可以在樹上維護一個標記的字首和,標記u,vu,v這一段所有的邊,表示這些邊屬於這個環,注意到可以通過u,vu,v深度差判斷該環是奇環還是偶環,如果是奇環則打上正標記,否則打上負標記,假設共有numnum個奇環,那麼被打上numnum個標記的邊都是合法邊,同時注意,若只有一個奇環,那麼那條非樹邊也是合法邊

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
const int maxn=1000005;
struct node
{
	int v,id,next;
}e[2*maxn];
int head[maxn],tot;
void add(int u,int v,int id)
{
	e[tot].v=v,e[tot].id=id,e[tot].next=head[u],head[u]=tot++;
}
int n,m,dep[maxn],num[maxn],vis[maxn],cir,self,not_tree;
vector<int>ans;
void dfs(int u,int fa)
{
	vis[u]=1;
	for(int i=head[u];~i;i=e[i].next)
	{
		if(i==fa)continue;
		int v=e[i].v;
		if(!vis[v])
		{
			dep[v]=dep[u]+1;
			dfs(v,i^1);
			num[u]+=num[v];
		}
		else
		{
			if(dep[v]>dep[u])continue;
			if((dep[u]-dep[v]+1)&1)num[u]++,num[v]--,cir++,not_tree=e[i].id;
			else num[u]--,num[v]++;
		}
	}
}
void dfs1(int u,int fa)
{
	vis[u]=1;
	if(num[u]==cir)ans.push_back(e[fa].id);
	for(int i=head[u];~i;i=e[i].next)
		if(!vis[e[i].v])dfs1(e[i].v,i);
}
int main()
{
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof(head));
	tot=0;
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		if(u==v)self++,ans.push_back(i);
		else add(u,v,i),add(v,u,i);
	}
	for(int i=1;i<=n;i++)
		if(!vis[i])
		{
			dep[i]=1;
			dfs(i,-1);
		}
	if(!cir)
	{
		if(self==0)
		{
			printf("%d\n",m);
			for(int i=1;i<=m;i++)printf("%d%c",i,i==m?'\n':' ');
		}
		else if(self==1)printf("1\n%d\n",ans[0]);
		else printf("0\n");
	}
	else
	{
		if(self)printf("0\n");
		else
		{
			memset(vis,0,sizeof(vis));
			for(int i=1;i<=n;i++)
				if(!vis[i])dfs1(i,-1);
			if(cir==1)ans.push_back(not_tree);
			printf("%d\n",ans.size());
			sort(ans.begin(),ans.end());
			for(int i=0;i<ans.size();i++)printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
		}
	}
	return 0;
}