传送门
这里主要是要注意到:
1.如果所有线段可以组成一颗最小生成树,那么边数一定是n-1。
2.那么如果可以组成2课不同种类的最小生成树,那么这2棵树的权值相等的边一定相等
所以只要判断每一个权值相等的边的集合有多少种组成方法,最后再相乘即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MX=1e5+9;
const int mod=31011;
int n,m,fa[MX],cnt=0,tot=0,sum=0,ans=1;
struct node{
int u,v;
ll len;
bool operator < (const node &a)const{
return len<a.len;
}
}t[MX];
struct Node{
int st,ed;
int val=0;
}tt[MX];
int fin(int a){
if( fa[a]==a )
return a;
else
return fin(fa[a]);
}
void dfs(int pos,int x,int val){
if( x==tt[pos].ed+1 ){
if( val==tt[pos].val )
sum++;
return ;
}
int u=fin(t[x].u),v=fin(t[x].v);
if( u!=v ){
fa[u]=v;
dfs(pos,x+1,val+1);
fa[u]=u;
fa[v]=v;
}
dfs(pos,x+1,val);
}
int main()
{
//freopen("input.txt","r",stdin);
scanf("%d %d",&n,&m);
for( int i=1 ; i<=m ; i++ )
scanf("%d %d %d",&t[i].u,&t[i].v,&t[i].len);
sort(t+1,t+m+1);
for( int i=1 ; i<=n ; i++ )
fa[i]=i;
for( int i=1 ; i<=m ; i++ ){
if( t[i].len!=t[i-1].len ){
tt[++cnt].st=i;
tt[cnt].ed=i;
tt[cnt-1].ed=i-1;
}
int x=fin(t[i].u),y=fin(t[i].v);
if( x!=y ){
fa[x]=y;
tt[cnt].val++;
tot++;
}
}
tt[cnt].ed=m;
for( int i=1 ; i<=n ; i++ )
fa[i]=i;
if( tot!=n-1 ){
printf("0\n");
return 0;
}
else{
for( int i=1 ; i<=cnt ; i++ ){
sum=0;
dfs(i,tt[i].st,0);
ans=(ans*sum)%mod;
for( int j=tt[i].st ; j<=tt[i].ed ; j++ ){
int x=fin(t[j].u),y=fin(t[j].v);
if( x!=y )
fa[x]=y;
}
}
}
printf("%d\n",ans);
return 0;
}