最小生成树计数(有一个神奇的操作)
有一个定理:无论最小生成树由哪些边组成,其中使用的每种边权的边的数量是一定的
所以由此我们可以得到一种做法:记录最小生成树使用的每种边的数量,然后dfs使用这些边去构建另一棵最小生成树
#include<bits/stdc++.h> using namespace std; const int mod=31011; int n,m,sum; struct node{ int x,y,w; }e[9999999]; struct Node{ int l,r,len; }a[9999999]; int pre[9999999]; bool cmp(node a,node b){ return a.w<b.w; } void read(int &x) { int f=1;x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } void print(int x) { if(x<0){putchar('-');x=-x;} if(x>9){print(x/10);} putchar(x%10+'0'); } int find(int x) { //return x==pre[x]?x:pre[x]=find(pre[x]); //写成x:pre[x]=find(pre[x]);不对 return x==pre[x]?x:find(pre[x]); //此题不该路径压缩 } void dfs(int x,int now,int k) { if(now==a[x].r+1) { if(k==a[x].len){ ++sum; } return; } int p=find(e[now].x),q=find(e[now].y); if(p!=q){ pre[p]=q; dfs(x,now+1,k+1); pre[p]=p;pre[q]=q; } dfs(x,now+1,k); } int main() { read(n),read(m); for(register int i=1;i<=n;++i) pre[i]=i; int tot=0,cnt=0,ans=1; for(register int i=1;i<=m;i++) read(e[i].x),read(e[i].y),read(e[i].w); sort(e+1,e+m+1,cmp); for(register int i=1;i<=m;++i) { if(e[i].w!=e[i-1].w) { a[++cnt].l=i; a[cnt-1].r=i-1; } int p=find(e[i].x); int q=find(e[i].y); if(p!=q) { pre[p]=q; a[cnt].len++; tot++; } } a[cnt].r=m; if(tot!=n-1){ putchar('0');return 0; } for(register int i=1;i<=n;i++) pre[i]=i; for(register int i=1;i<=cnt;++i) { sum=0; dfs(i,a[i].l,0); ans=(ans*sum)%mod; for(register int j=a[i].l;j<=a[i].r;++j) { int p=find(e[j].x),q=find(e[j].y); if(p!=q){ pre[p]=q; } } } print(ans); return 0; }