我的天,改一個晚上才改出來,一個及其細微難以發現的邏輯錯誤:在做最小生成樹順便保留並查集狀態的時候,不論每次是否處理的是新的種類的邊(離散化後的),都應當先將fa拷貝到nowfa當中去,否則將會出現一種邊沒有被使用過(因爲加入後會形成環),從而其相對應的nowfa均爲0,導致在dfs判斷所選則的邊會不會形成環時得出有環的結論(因爲fa[a]、fa[b]都是0),進而引起方案數出現0的情況。
#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
using namespace std;
typedef long long ll;
const int inf=1e9+10,mod=31011,N=666,M=2222;
const double eps=1e-6;
struct edge{
int a,b,w;
bool friend operator < (edge a,edge b){
return a.w<b.w;
}
}e[M];
int n,m,cnt[M],fa[N];//cnt[i]表示權值排第i的邊在最小生成樹用到了幾條。
int nowfa[M][N],st[N],ret;
ll ans=1;
int getf(int v){ return fa[v]==v?v:fa[v]=getf(fa[v]);}
bool selected[M];
int tmpfa[N];
int tmpgetf(int v) { return tmpfa[v]==v?v:tmpfa[v]=tmpgetf(tmpfa[v]);}
void dfs(int v,int pos,int sel){
if(sel==cnt[v]){
memcpy(tmpfa,nowfa[v-1],sizeof(nowfa[v-1]));
rep(i,st[v],pos) if(selected[i]){
int faa=tmpgetf(e[i].a),fab=tmpgetf(e[i].b);
if(faa==fab) return;
tmpfa[fab]=faa;
}
ret++;
return;
}
if(pos>=st[v+1])return;
dfs(v,pos+1,sel);
selected[pos]=true;
dfs(v,pos+1,sel+1);
selected[pos]=false;
}
void process(int v){
ret=0;
if(cnt[v]==0) return;
dfs(v,st[v],0);
ans=(ans*(ll)ret)%mod;
return;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0);
cin>>n>>m;
rep(i,1,m) cin>>e[i].a>>e[i].b>>e[i].w;
sort(e+1,e+1+m);
int now=0,num=0;
rep(i,1,m){//離散化處理
if(e[i].w!=now){
now=e[i].w;
e[i].w=++num;
st[e[i].w]=i;
}else e[i].w=num;
}
st[e[m].w+1]=m+1;
rep(i,1,n) fa[i]=i;
int last=0,tot=0;
rep(i,1,m){
int faa=getf(e[i].a),fab=getf(e[i].b);
memcpy(nowfa[last],fa,sizeof(fa));
last=e[i].w;
if(faa==fab) continue;
cnt[e[i].w]++; fa[fab]=faa; tot++;
}
if(tot<n-1){
cout<<0;
return 0;
}
rep(i,1,num) process(i);//處理權值爲i的邊
cout<<ans;
return 0;
}