版权声明:发现蒟蒻ff_666,但转载请注明 https://blog.csdn.net/qq_42403731/article/details/82018904
这题,需要知道最小生成树三定理
然后就很简单了。。
对于每种相同边权进行
的枚举,乘法原理统计答案。。
#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
using namespace std;
static char buf[1000000],*p1=buf,*p2=buf;
const int maxE=(1e4)+5,maxn=105,TT=31011;
int n,m,tot,fa[maxn],cnt[maxn],S,Ans=1,lnk[1005][1005];
struct Edges{
int x,y,w;
bool operator <(const Edges b)const{return w<b.w;}
}E[maxE],val[maxE];
int read(){
int ret=0;char ch=gt();
while(ch<'0'||ch>'9') ch=gt();
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
return ret;
}
int getfa(int x){return fa[x]==x?x:getfa(fa[x]);}//路径压缩不支持撤销不能压
void DFS(int st,int p,int hsh){
if(hsh==val[p].w) return (void)(++S);
if(val[p].y-st+1+hsh<val[p].w) return;
int fx=getfa(E[st].x),fy=getfa(E[st].y);
if(fx!=fy){
int cfx=cnt[fx],cfy=cnt[fy];
if(cnt[fx]<cnt[fy]) cnt[fy]+=cnt[fx],fa[fx]=fy;else cnt[fx]+=cnt[fy],fa[fy]=fx;
DFS(st+1,p,hsh+1);
fa[fx]=fx,fa[fy]=fy,cnt[fx]=cfx,cnt[fy]=cfy;
}
DFS(st+1,p,hsh);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) fa[i]=i,cnt[i]=1;
for(int i=1;i<=m;i++) E[i]=(Edges){read(),read(),read()};sort(E+1,E+1+m);
int D=0;
for(int i=1,fx,fy;i<=m;i++){
if(E[i].w!=E[i-1].w) val[++tot]=(Edges){i,i,0},val[tot-1].y=i-1;
if((fx=getfa(E[i].x))!=(fy=getfa(E[i].y))){
val[tot].w++,D++;
if(cnt[fx]<cnt[fy]) cnt[fy]+=cnt[fx],fa[fx]=fy;else cnt[fx]+=cnt[fy],fa[fy]=fx;
}
}
if(D!=n-1) return puts("0"),0;
val[tot].y=m;
for(int i=1;i<=n;i++) fa[i]=i,cnt[i]=1;
for(int i=1,fx,fy;i<=tot;i++){
S=0,DFS(val[i].x,i,0);
(Ans*=S)%=TT;
for(int j=val[i].x;j<=val[i].y;j++)if((fx=getfa(E[j].x))!=(fy=getfa(E[j].y)))
if(cnt[fx]<cnt[fy]) cnt[fy]+=cnt[fx],fa[fx]=fy;else cnt[fx]+=cnt[fy],fa[fy]=fx;
}
printf("%d\n",Ans);
return 0;
}