zoukankan      html  css  js  c++  java
  • P4208 [JSOI2008]最小生成树计数

    题目

    P4208 [JSOI2008]最小生成树计数

    以前一直以为JSOI的题应该比较水吧,果然还是我太ruo了

    做法

    两个性质
    (1.):最小生成树中同一权值的边数一定
    (2.):最小生成树中同一权值的边连接后联通块状态相同

    利用这两个性质,开两个数组维护所属联通块(并查集),每次处理同一边权的点

    假设我们上一次权值的记录为(last),实时更新的为(fa)

    处理此权值边:如果在last中的两点没联通那标记一下这是可用的,让这些点形成树,存在有些在处理此边权时联通,会形成环,这些不是不能选,因为我们用的方法是分治形成树,用这些边单独形成一棵树,显然所有权值的边最后会形成一棵大树,所以我们这里记录祖先是用的联通之前的,然后更新祖先是实时更新的(可以理解为处理一个权值后就把那些缩点)

    然后处理同一权值,这些块可能不止一个就分开计算这些边能形成的树,矩阵树就行了

    My complete code

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<ctime>
    #include<vector>
    using namespace std;
    typedef int LL;
    const LL maxn=200;
    const LL p=31011;
    inline LL Read(){
    	LL x(0),f(1); char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') f=-1; c=getchar();
    	}
    	while(c>='0'&&c<='9')
    	    x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x*f;
    }
    struct node{
    	LL u,v,d;
    }e[maxn*maxn];
    LL n,m;
    LL g[maxn][maxn],D[maxn][maxn];
    inline bool cmp(node x,node y){
    	return x.d<y.d;
    }
    LL Get_fa(LL u,LL *fa){
    	return fa[u]=(fa[u]==u)?u:Get_fa(fa[u],fa);
    }
    inline LL Calc(LL N){
    	LL tr(0),ret(1);
    	for(LL i=1;i<=N;++i){
    		for(LL j=i+1;j<=N;++j){
    			while(D[j][i]){
    				LL tmp=D[i][i]/D[j][i];
    				for(LL k=1;k<=N;++k){
    					D[i][k]=(D[i][k]-tmp*D[j][k]%p+p)%p;
    					swap(D[i][k],D[j][k]);
    				}
    				tr^=1;
    			}
    		}
    		if(D[i][i]==0)
    		    return 0;
    		ret=ret*D[i][i]%p;
    	}
    	if(tr)
    	    ret=p-ret;
    	return ret;
    }
    LL ans=1;
    LL fa[maxn],last[maxn];
    bool visit[maxn];
    vector<LL> belong[maxn];
    inline void Solve(){
    	for(LL i=1;i<=n;++i)
    	    if(visit[i])
    	        belong[Get_fa(i,fa)].push_back(i),
    	        visit[i]=false;
    	LL ret(1);
    	for(LL i=1;i<=n;++i){
    		LL size(belong[i].size());
    		if(size<=1)
    		    continue;
    		memset(D,0,sizeof(D));
    		for(LL j=1;j<=size;++j){
    			LL u(belong[i][j-1]);
    			for(LL k=j+1;k<=size;++k){
    				LL v(belong[i][k-1]);
    				if(g[u][v]){
    					D[j][k]=D[k][j]=(p-g[u][v])%p,
    					D[j][j]+=g[u][v],D[k][k]+=g[u][v];
    				}
    			}
    		}
    		ans=(ans*Calc(size-1))%p;
    		for(LL j=1;j<=size;++j)
    			last[belong[i][j-1]]=i;
    	}
    	for(LL i=1;i<=n;++i)
    	    belong[i].clear(),
    	    fa[i]=last[i]=Get_fa(i,last);
    }
    int main(){
    	n=Read(),m=Read();
    	for(LL i=1;i<=m;++i)
    	    e[i].u=Read(),e[i].v=Read(),e[i].d=Read();
    	sort(e+1,e+1+m,cmp);
    	e[0]=e[1];
    	for(LL i=1;i<=n;++i)
    	    last[i]=fa[i]=i;
    	for(LL i=1;i<=m;++i){
    		if(e[i].d^e[i-1].d){
    		    Solve();
    		    memset(g,0,sizeof(g));
    		}
    		LL u(e[i].u),v(e[i].v);
    		LL fu(Get_fa(u,last)),fv(Get_fa(v,last)) ;
    		if(fu^fv){
    			visit[fu]=visit[fv]=true;
    			++g[fu][fv]; ++g[fv][fu];
    			fa[Get_fa(fu,fa)]=Get_fa(fv,fa);
    		}
    	}Solve();
    	for(LL i=2;i<=n;++i)
    	    if(last[i]^last[i-1]){
    	    	printf("0");
    	    	return 0;
    		}
    	printf("%d",ans);
    	return 0;
    }/*
    */
    
  • 相关阅读:
    【HDU5015】233 Matrix
    【POJ3233】Matrix Power Series
    【POJ3070】Fibonacci
    【NOIP模拟】奇怪的字符串
    【NOIP模拟】超级跳棋
    【NOIP模拟】玛雅文字
    【NOIP模拟】距离
    【闲聊】关于本BLOG
    【NOIP模拟】树
    【NOIP模拟】机器人
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10269965.html
Copyright © 2011-2022 走看看