DTOJ#5224. 分组

传送门

H 所带的班级共有 n n n 位学生,为了提高学习成绩,小 H 建立了 k k k 个学习小组,第 i i i 个学生是第 a i a_i ai 个学习小组的成员。

在这 n n n 个学生当中,有 m m m 对好朋友,一对好朋友如果一起学习的话,一部分时间都在聊天,这样不仅无法高效学习,并且会干扰他人,小 H 很讨厌这种情况的发生。

为了解决这个问题,小 H 想出了一个办法,他想将所有学生重新分组,以保证没有一对好朋友在同一个学习小组。

由于这个工作过于复杂,小 H 想从最简单的工作做起。他想知道,如果只选择两个学习小组的成员并将他们重新分成两组,有多少种选法能满足所有好朋友都不同组。

重新分组后只需要考虑这两组内分别没有好朋友即可,即不用考虑其他组。

第一行三个正整数,分别表示 n , m , k n,m,k n,m,k

第二个正整数,第 i i i 个数表示 a i a_i ai

接下来 m m m 行,每行两个整数 x , y x,y x,y,表示第 x x x 个学生和第 y y y 个学生是好朋友。

一个整数表示有多少种满足要求的选择学习小组的方法。

样例输入1

6 8 3
1 1 2 2 3 3
1 3
1 5
1 6
2 5
2 6
3 4
3 5
5 6

样例输出1

2

样例输入2

5 5 2
1 2 1 2 1
1 2
2 3
3 4
4 5
5 1

样例输出2

0

对于 10% 的数据, n , m , k ≤ 10 n,m,k \le 10 n,m,k10

对于 30% 的数据, n , m , k ≤ 100 n,m,k \le 100 n,m,k100

对于 50% 的数据, n , m , k ≤ 5 × 1 0 3 n,m,k \le 5 \times 10^3 n,m,k5×103

对于 100% 的数据, 1 ≤ n , m , k ≤ 5 × 1 0 5 , 1 ≤ a i ≤ k , 1 ≤ x , y ≤ n 1 \le n,m,k \le 5 \times 10^5, 1 \le a_i \le k,1 \le x,y \le n 1n,m,k5×105,1aik,1x,yn

首先发现就是二分图判定。
这时思考:二分图判定①不存在奇环②拆点,奇偶点不属于同一块。
显然②简单。于是我们用可回退化并查集维护。
总时间 O ( m l o g n ) O(mlogn) O(mlogn)

#include<bits/stdc++.h>
#define N 1000005
typedef long long ll;
using namespace std;
int read(){
    
    
	int op=1,sum=0;char ch=getchar();
	while(ch<'0'||ch>'9') {
    
    if(ch=='-') op=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+ch-'0',ch=getchar();
	return op*sum;
} 
int od[N],ev[N],a[N];
struct node{
    
    
	int u,v,x,y;
}b[N];
int bt;
bool cmp(node x,node y){
    
    if(x.u==y.u)return x.v<y.v;return x.u<y.u;}
int sta[N][2],top,fa[N],sz[N],biao[N];
inline int get(int x){
    
    return fa[x]==x?x:get(fa[x]);}
inline void merge(int x,int y){
    
    
	int fx=get(x),fy=get(y);
	if(fx==fy)return ;
	if(sz[fx]<sz[fy])swap(fx,fy);
	sta[++top][0]=fx,sta[top][1]=fy;
	fa[fy]=fx;sz[fx]+=sz[fy];
}
int main(){
    
    
	int n=read(),m=read(),k=read();
	for(int i=1;i<=n;++i){
    
    
	    a[i]=read();
	    od[i]=2*i;ev[i]=od[i]|1;
	}
	for(int i=1;i<=ev[n];++i)fa[i]=i,sz[i]=1;
	ll sum=0;
	for(int i=1;i<=m;++i){
    
    
		int x=read(),y=read();
		if(a[x]>a[y])swap(x,y);
		if(a[x]!=a[y]){
    
    
			++bt;
			b[bt].u=a[x],b[bt].x=x,b[bt].v=a[y],b[bt].y=y;
		}else{
    
    
			merge(od[x],ev[y]);merge(ev[x],od[y]);
			if(get(od[x])==get(ev[x])||get(od[y])==get(ev[y]))biao[a[x]]=1;
		}
	}
	sort(b+1,b+1+bt,cmp);
	for(int i=1;i<=k;++i)sum+=biao[i];
	ll ans=1ll*(k-sum)*(k-1-sum)/2;
	for(int i=1,j=i;i<=bt;i=j){
    
    
		j=i;int flag=(biao[b[j].u]|biao[b[j].v]);
		top=0;
		while(j<=bt&&b[j].u==b[i].u&&b[j].v==b[i].v){
    
    
			int x=b[j].x,y=b[j].y;
			merge(od[x],ev[y]);merge(ev[x],od[y]);
			if(get(od[x])==get(ev[x])||get(od[y])==get(ev[y]))flag|=1;
			++j;
		}
		while(top){
    
    
			int x=sta[top][0],y=sta[top][1];
			fa[y]=y;sz[x]-=sz[y];
			--top;
		}
		if(biao[b[i].u]||biao[b[i].v])continue;
		ans-=flag;
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CSDNzhanghongyu/article/details/110499589