[JZOJ5153]树形图求和

来源:互联网 发布:淘宝一千零一夜几点看 编辑:程序博客网 时间:2024/05/16 14:44

题目大意

给定一个n个点m条边的带权有向图,每条边描述为(ui,vi,wi)不存在自环,可能有重边。
请计算出所有的以n为根的有向生成树(在本题定义为所有边从儿子指向父亲)的权值和,一棵树的权值定义为其所有边的权值和。

2n300,0m105,1ui,vin,1wi109


题目分析

在我的Matrix-Tree定理学习小记(详细介绍+证明)中你可以找到基尔霍夫定理在有向图上的推广。
如果只是求方案数的话直接有向图基尔霍夫矩阵树定理做,求出Mnn就好了,可是这题里面我们要计算权值和。
怎么办呢?我们定义一种新的数(a,b),它代表了权值和为b的一个局部生成树有a种方案。定义其加法为直接相加,表示两种互相独立的方案,减法是加法逆运算;乘法为(ab,ad+bc),意义为两种方案的合并。定义其除法为乘法的逆运算,即(ac,bcadc2)。单位元为(1,0),零元为(0,0)
然后用这种新的数代替原本的数做基尔霍夫定理就好了。加入一条边直接在邻接矩阵对应位置加上(1,wi),度数矩阵类似。消元过程和普通的数的运算一致,要把下三角消成零元。然后答案就是行列式得出来的数的第二项。
时间复杂度O(n3)


代码实现

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <cctype>using namespace std;int read(){    int x=0,f=1;    char ch=getchar();    while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();    return x*f;}const int P=1000000007;const int N=305;typedef pair<int,int> PI;#define mkp(a,b) make_pair(a,b)#define ft first#define sd secondint sqr(int x){return 1ll*x*x%P;}int quick_power(int x,int y){    int ret=1;    for (;y;y>>=1,x=1ll*x*x%P) if (y&1) ret=1ll*ret*x%P;    return ret;}PI operator+(PI x,PI y){return mkp((x.ft+y.ft)%P,(x.sd+y.sd)%P);}PI operator+=(PI &x,PI y){return x=x+y;}PI operator-(PI x){return mkp(P-x.ft,P-x.sd);}PI operator-(PI x,PI y){return x+(-y);}PI operator-=(PI &x,PI y){return x=x-y;}PI operator*(PI x,PI y){return mkp(1ll*x.ft*y.ft%P,(1ll*x.ft*y.sd%P+1ll*x.sd*y.ft%P)%P);}PI operator*=(PI &x,PI y){return x=x*y;}PI operator/(PI x,PI y){    int inv=quick_power(y.ft,P-2);    return mkp(1ll*x.ft*inv%P,1ll*(1ll*x.sd*y.ft%P-1ll*x.ft*y.sd%P+P)%P*sqr(inv)%P);}PI tmp[N][N];struct matrix{    PI num[N][N];    int s;    PI det()    {        memcpy(tmp,num,sizeof num);bool sig=1;        for (int i=0;i<s;++i)        {            if (!tmp[i][i].ft)                for (int j=i+1;j<s;++j)                    if (tmp[j][i].ft)                    {                        sig^=1;                        for (int k=i;k<s;++k) swap(tmp[i][k],tmp[j][k]);                        break;                    }            if (!tmp[i][i].ft) continue;            PI inv=mkp(1,0)/tmp[i][i],mul;            for (int j=i+1;j<s;++j)                if (tmp[j][i].ft)                {                    mul=tmp[j][i]*inv;                    for (int k=i;k<s;++k) tmp[j][k]-=tmp[i][k]*mul;                }        }        PI ret=mkp(1,0);        for (int i=0;i<s;++i) ret*=tmp[i][i];        return sig?ret:-ret;    }}Kir;int n,m;int main(){    freopen("calc.in","r",stdin),freopen("calc.out","w",stdout);    n=read(),m=read(),Kir.s=n;    for (int i=1,x,y,z;i<=m;++i)    {        x=read()-1,y=read()-1,z=read(),swap(x,y);        Kir.num[y][y]+=mkp(1,z),Kir.num[x][y]-=mkp(1,z);    }    --Kir.s,printf("%d\n",Kir.det().sd);    fclose(stdin),fclose(stdout);    return 0;}
原创粉丝点击