小 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,k≤10。
对于 30% 的数据, n , m , k ≤ 100 n,m,k \le 100 n,m,k≤100。
对于 50% 的数据, n , m , k ≤ 5 × 1 0 3 n,m,k \le 5 \times 10^3 n,m,k≤5×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 1≤n,m,k≤5×105,1≤ai≤k,1≤x,y≤n 。
首先发现就是二分图判定。
这时思考:二分图判定①不存在奇环②拆点,奇偶点不属于同一块。
显然②简单。于是我们用可回退化并查集维护。
总时间 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;
}