根据Kruscal算法的过程 我们可以得到一些结论
来自 这里
- 如果
A,B
同为
G
的最小生成树,且
A 的边权从小到大为 w(a1),w(a2),w(a3),⋯w(an) , B 的边权从小到大为w(b1),w(b2),w(b3),⋯w(bn) ,则有 w(ai)=w(bi) 。 - 如果
A,B
同为
G
的最小生成树,如果
A,B 都从零开始从小到大加边( A 加A 的边, B 加B 的边)的话,每种权值加完后图的联通性相同。 - 如果在最小生成树
A
中权值为
v 的边有 k 条,用任意k 条权值为 v 的边替换A 中的权为 v <script type="math/tex" id="MathJax-Element-21">v</script> 的边且不产生环的方案都是一棵合法最小生成树。
然后就可以干些奇奇怪怪的事情 按边权分阶段 然后这些边会把某些连通块缩成一个大连通块 这些大连通块之间互不影响 只要对这些大连通块分别做矩阵树定理求余子式 用乘法原理就好了
可能还是这里讲的比较清楚啊
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=105;
const int M=1005;
const int P=31011;
struct Tset{
int fat[N];
void init(int n){ for (int i=1;i<=n;i++) fat[i]=i; }
int Fat(int u){ return u==fat[u]?u:fat[u]=Fat(fat[u]); }
}S1,S2;
struct edge{
int u,v,w;
bool operator < (const edge &B) const{ return w<B.w; }
}ed[M];
int n,m,ans=1;
int A[N][N];
int sta[N][N],top[N];
int a[N][N];
inline int det(int n){
int ret=1;
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][j]=(a[i][j]%P+P)%P;
for (int i=1;i<=n;i++){
for (int j=i+1;j<=n;j++)
while (a[j][i]){
int t=a[i][i]/a[j][i];
for (int k=i;k<=n;k++) a[i][k]=(a[i][k]+P-a[j][k]*t%P)%P;
for (int k=i;k<=n;k++) swap(a[i][k],a[j][k]);
ret=P-ret;
}
if (!a[i][i]) return 0;
ret=ret*a[i][i]%P;
}
return ret;
}
int main(){
int last=0;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m); if (m<n-1) return printf("0\n"),0;
for (int i=1;i<=m;i++) read(ed[i].u),read(ed[i].v),read(ed[i].w);
sort(ed+1,ed+m+1); S1.init(n); S2.init(n);
for (int i=1;i<=m+1;i++){
if ((i>1 && ed[i].w!=ed[i-1].w) || i==m+1){
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]++,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]++;
for (int j=1;j<=n;j++)
if (S2.Fat(j)==j)
sta[S1.Fat(j)][++top[S1.Fat(j)]]=j;
for (int j=1;j<=n;j++)
if (top[j]>1){
for (int k=1;k<=top[j];k++) a[k][k]=0;
for (int k=1;k<=top[j];k++)
for (int l=k+1;l<=top[j];l++){
int x=sta[j][k],y=sta[j][l];
a[k][l]=-A[x][y]; a[l][k]=-A[x][y];
a[k][k]+=A[x][y]; a[l][l]+=A[x][y];
}
(ans*=det(top[j]-1))%=P;
}
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]--,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]--;
for (int j=1;j<=n;j++)
S2.fat[j]=S1.Fat(j),top[j]=0;
last=i;
}
int x=S1.Fat(ed[i].u),y=S1.Fat(ed[i].v);
if (x==y) continue;
S1.fat[x]=y;
}
int cnt=0;
for (int i=1;i<=n;i++)
cnt+=S1.Fat(i)==i;
printf("%d\n",cnt==1?ans:0);
return 0;
}
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=105;
const int M=1005;
struct Tset{
int fat[N];
void init(int n){ for (int i=1;i<=n;i++) fat[i]=i; }
int Fat(int u){ return u==fat[u]?u:fat[u]=Fat(fat[u]); }
}S1,S2;
struct edge{
int u,v,w;
bool operator < (const edge &B) const{ return w<B.w; }
}ed[M];
int n,m,ans,P;
int A[N][N];
int sta[N][N],top[N];
int a[N][N];
inline int det(int n){
int ret=1;
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][j]=(a[i][j]%P+P)%P;
for (int i=1;i<=n;i++){
for (int j=i+1;j<=n;j++)
while (a[j][i]){
int t=a[i][i]/a[j][i];
for (int k=i;k<=n;k++) a[i][k]=(a[i][k]+P-(ll)a[j][k]*t%P)%P;
for (int k=i;k<=n;k++) swap(a[i][k],a[j][k]);
ret=P-ret;
}
if (!a[i][i]) return 0;
ret=(ll)ret*a[i][i]%P;
}
return ret;
}
int main(){
int last;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
while (1){
read(n); read(m); read(P); if (!n && !m && !P) break;
ans=1; last=0;
for (int i=1;i<=m;i++) read(ed[i].u),read(ed[i].v),read(ed[i].w);
if (m<n-1) { printf("0\n"); continue; }
sort(ed+1,ed+m+1); S1.init(n); S2.init(n);
for (int i=1;i<=m+1;i++){
if ((i>1 && ed[i].w!=ed[i-1].w) || i==m+1){
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]++,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]++;
for (int j=1;j<=n;j++)
if (S2.Fat(j)==j)
sta[S1.Fat(j)][++top[S1.Fat(j)]]=j;
for (int j=1;j<=n;j++)
if (top[j]>1){
for (int k=1;k<=top[j];k++) a[k][k]=0;
for (int k=1;k<=top[j];k++)
for (int l=k+1;l<=top[j];l++){
int x=sta[j][k],y=sta[j][l];
a[k][l]=-A[x][y]; a[l][k]=-A[x][y];
a[k][k]+=A[x][y]; a[l][l]+=A[x][y];
}
ans=(ll)ans*det(top[j]-1)%P;
}
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]--,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]--;
for (int j=1;j<=n;j++)
S2.fat[j]=S1.Fat(j),top[j]=0;
last=i;
}
int x=S1.Fat(ed[i].u),y=S1.Fat(ed[i].v);
if (x==y) continue;
S1.fat[x]=y;
}
int cnt=0;
for (int i=1;i<=n;i++) cnt+=S1.Fat(i)==i;
printf("%d\n",cnt==1?ans%P:0);
}
return 0;
}