【解题思路】
Kruskal的拓展。
可以先对边排序,进行一次Kruskal,判断是否可行,并计算出每种权值的边需要多少条。
然后暴力统计每种权值可行的方案数,根据乘法原理乘起来即可。复杂度o(210mlog2(m+α(n)))。
【参考代码】
1 #pragma GCC optimize(2) 2 #include <algorithm> 3 #define REP(i,low,high) for(register int i=(low);i<=(high);++i) 4 using namespace std; 5 6 //quick_io { 7 #include <cctype> 8 #include <cstdio> 9 inline long long getint() 10 { 11 char ch=getchar(); for(;!isdigit(ch)&&ch!='+'&&ch!='-';ch=getchar()); 12 short sig=1; for(;ch=='+'||ch=='-';ch=getchar()) if(ch=='-') sig*=-1; 13 long long ret=0; for(;isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-'0'; 14 return sig*ret; 15 } 16 //} quick_io 17 18 //find_union_set { 19 #include <cstring> 20 class find_union_set 21 { 22 private:int fat[110],stk[110]; 23 int find(const int&element) 24 { 25 int ancestor=element,top=0; 26 for(;ancestor!=fat[ancestor];ancestor=fat[ancestor]) stk[top++]=ancestor; 27 for(;top--;fat[stk[top]]=ancestor); return ancestor; 28 } 29 public: 30 find_union_set() {REP(i,1,100) fat[i]=i;} void clear() {REP(i,1,100) fat[i]=i;} 31 find_union_set&operator=(const find_union_set&thr) 32 { 33 return memcpy(fat,thr.fat,sizeof thr.fat),*this; 34 } 35 bool same(const int&one,const int&thr) {return find(one)==find(thr);} 36 bool unite(const int&one,const int&thr) 37 { 38 return same(one,thr)?0:(fat[fat[one]]=fat[thr],1); 39 } 40 }; 41 //} find_union_set 42 43 struct edge 44 { 45 int fr,to,vl; 46 void input() {fr=getint(),to=getint(),vl=getint();} 47 bool operator<(const edge&thr)const{return vl<thr.vl;} 48 }edg[1010]; 49 50 static const int AwD=31011; int cnt[1010]={0}; find_union_set now,tmp,can; 51 int main() 52 { 53 int n=getint(),m=getint(); REP(i,1,m) edg[i].input(); sort(edg+1,edg+m+1); 54 int tot=0,ans=1; REP(i,1,m) 55 { 56 tot+=edg[i].vl!=edg[i-1].vl; 57 if(!now.same(edg[i].fr,edg[i].to)) now.unite(edg[i].fr,edg[i].to),++cnt[tot]; 58 } 59 REP(i,2,n) if(!now.same(1,i)) return puts("0"),0; now.clear(); 60 for(register int i=1,j=1,tot=1;i<=m;i=++j,++tot,now=can) 61 { 62 for(;j<=m&&edg[j].vl==edg[i].vl;++j); --j; int count=0; 63 for(register int status=1<<j-i+1;status--;) 64 if(__builtin_popcount(status)==cnt[tot]) 65 { 66 tmp=now; bool flag=0; REP(k,i,j) if(status&(1<<k-i)) 67 { 68 if(flag=!tmp.unite(edg[k].fr,edg[k].to)) break; 69 } 70 if(!flag) {can=tmp; if(++count==AwD) count=0;} 71 } 72 (ans*=count)%=AwD; 73 } 74 return printf("%d\n",ans),0; 75 }
We Secure, We Contain, We Protect.