[JSOI2008]最小生成树计数

传送门

Description

最小生成树计数

Solution 

首先,考虑kruskal的过程,发现相同权值的边的集合对生成树的贡献是一样的

所以对权值排序按照从小到大的顺序

分别根据\(Matrix-tree\)做生成树计数

每个权值处理完,都缩点一下

为了好写,可以把很多联通块连在一起做

Code 

/*最小生成树计数 */ 
#include<bits/stdc++.h>
#define ll long long
#define dbg1(x) cerr<<#x<<"="<<(x)<<" "
#define dbg2(x) cerr<<#x<<"="<<(x)<<"\n"
#define dbg3(x) cerr<<#x<<"\n"
using namespace std;
#define reg register
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const int P=919260817,MN=305,ME=1e5+5;
int K[MN][MN];
int Mul(int x,int y){return (1ll*x*y)%P;}
int Add(int x,int y){return (x+y)%P;}
int Dec(int x,int y){return Add(x,P-y);}
int MatT(int &n)
{
	int r=1,t;reg int i,j,k;
	for(i=1;i<n;++i)
	{
		for(j=i+1;j<n;++j)while(K[j][i])
		{
			t=K[i][i]/K[j][i];
			if(t)for(k=i;k<n;++k)
			K[i][k]=Dec(K[i][k],Mul(K[j][k],t));
			swap(K[i],K[j]);r=Dec(0,r);
		}
		r=Mul(r,K[i][i]);if(!r) return r;
	}
	return r;
}
int N,M,fa[MN],re[MN],tt,st[MN],ans,ff[MN];
int getf(int *f,int x){return f[x]==x?x:f[x]=getf(f,f[x]);}
void union_(int *f,int x,int y){x=getf(f,x);y=getf(f,y);if(x!=y)f[y]=x;}
struct edge{int x,y,w;}e[ME];
bool cmp(edge x,edge y){return x.w<y.w;}
vector<int>G[MN];
void ins(int x,int y){++K[x][x],++K[y][y],K[x][y]=Dec(K[x][y],1),K[y][x]=Dec(K[y][x],1);}
int main()
{
	freopen("crazy.in","r",stdin);
	freopen("crazy.out","w",stdout);
	N=read(),M=read();
	reg int l,r,i,j,x,y;
	for(i=1;i<=N;++i)fa[i]=ff[i]=i;
	for(i=1;i<=M;++i)e[i].x=read(),e[i].y=read(),e[i].w=read();
	std::sort(e+1,e+M+1,cmp);
	for(ans=l=1,r=0;l<=M;++l)
	{
		while(e[r+1].w==e[l].w)++r;
		for(tt=0,i=l;i<=r;++i)
		{
			x=getf(fa,e[i].x);y=getf(fa,e[i].y);if(x==y)continue;
			if(!re[x])re[x]=++tt,st[tt]=x;x=re[x];
			if(!re[y])re[y]=++tt,st[tt]=y;y=re[y];
			ins(x,y);union_(ff,x,y);
		}
		if(!tt)continue;
		for(j=getf(ff,1),i=1;i<=tt;++i)if(getf(ff,i)==i&&ff[i]!=j)ins(j,i);
		ans=Mul(ans,MatT(tt));
		for(i=1;i<=tt;++i)re[st[i]]=0;
		for(i=1;i<=tt;++i)ff[i]=i;
		for(i=1;i<=tt;++i)for(j=1;j<=tt;++j)K[i][j]=0;
		for(i=l;i<=r;++i)union_(fa,e[i].x,e[i].y);l=r;
	}
	for(i=1,j=0;i<=N;++i)j+=i==getf(fa,i);
	if(j>1)printf("0\n");else printf("%d\n",ans);
	return 0;
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2019-11-01 16:09  PaperCloud  阅读(196)  评论(0编辑  收藏  举报