codeforces #309 div1 C

首先我们会发现所有的人构成了一个图

定义相爱为 在一个集合里

定义相恨为 不在一个集合里

很容易发现满足条件的图一定是一个二分图

那么分类讨论如下:

1、如果出现不合法 答案为0

2、如果不是一个二分图 答案为0

3、设图中联通块有k个,那么答案为2^k/2! = 2^(k-1)

那么算法很明了了

将相爱的人用并查集缩点并判断不合法

之后相恨的人之间相互连边并进行二分图染色判定

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=100010;
const int mod=1e9+7;
int n,m;
int co[maxn];
struct Edge{
	int u,v,type;
}c[maxn];
int h[maxn],cnt=0;
int fa[maxn];
struct edge{
	int to,next;
}G[maxn<<2];

int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);}
void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;}
LL pow_mod(LL v,int p){
	LL tmp=1;
	while(p){
		if(p&1)tmp=tmp*v%mod;
		v=v*v%mod;p>>=1;
	}return tmp;
}
bool paint(int u){
	for(int i=h[u];i;i=G[i].next){
		int v=G[i].to;
		if(co[v]){
			if(co[v]==co[u])return false;
		}else{
			co[v]=3-co[u];
			if(!paint(v))return false;
		}
	}return true;
}
int Get_color(){
	int ans=0;
	for(int i=1;i<=n;++i){
		if(ufs(i)!=i)continue;
		if(co[i])continue;
		ans++;co[i]=1;
		if(!paint(i))return -1;
	}return ans;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i)scanf("%d%d%d",&c[i].u,&c[i].v,&c[i].type);
	for(int i=1;i<=n;++i)fa[i]=i;
	for(int i=1;i<=m;++i){
		if(c[i].type){
			int d1=ufs(c[i].u),d2=ufs(c[i].v);
			if(d1!=d2)fa[d1]=d2;
		}
	}
	for(int i=1;i<=m;++i){
		if(!c[i].type){
			int d1=ufs(c[i].u),d2=ufs(c[i].v);
			if(d1==d2){printf("0
");return 0;}
			add(d1,d2);add(d2,d1);
		}
	}
	int k=Get_color();
	if(k==-1)printf("0
");
	else printf("%I64d
",pow_mod(2LL,k-1));
	return 0;
}

  

原文地址:https://www.cnblogs.com/joyouth/p/5361984.html