模板:矩阵树定理

文章目录

  • 前言
  • 解析
    • 无向图
    • 有向图
      • 根向树
      • 叶向树
      • code
    • 带权图
      • code

所谓矩阵树定理,就是用矩阵解决树问题的定理。

(逃)

前言

神奇科技。
之前一直没有写博客,觉得还是写一发比较好。
证明什么的是不可能会的
背下来背下来!

解析

无向图

定义一个矩阵 AAA
Ai,i=diAi,j=−#(i,j)(i≠j)A_{i,i}=d_i\\A_{i,j}=-\#(i,j)(i\ne j)Ai,i=diAi,j=#(i,j)(i=j)
其中 #(i,j)\#(i,j)#(i,j) 表示这条边的数量。
求出这个矩阵的任意一个余子式即可。

有向图

根向树

定义一个矩阵 AAA
Ai,i=di+Ai,j=−#(i,j)(i≠j)A_{i,i}=d_i^+\\A_{i,j}=-\#(i,j)(i\ne j)Ai,i=di+Ai,j=#(i,j)(i=j)
去掉第 iii 行得到的余子式就是以 iii 为根的答案。

叶向树

定义一个矩阵 AAA
Ai,i=di−Ai,j=−#(i,j)(i≠j)A_{i,i}=d_i^-\\A_{i,j}=-\#(i,j)(i\ne j)Ai,i=diAi,j=#(i,j)(i=j)
唯一的区别就是主对角线从出度变成了入度(为什么呢?因为根的思想太陈旧,已经out

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;const int N=305;
const int mod=1e9+7;inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}int n,m;
ll a[N][N];
ll calc(int n){ll ans(1);for(int i=1;i<=n;i++){for(int j=i;j<=n;j++){if(a[j][i]){if(j!=i) swap(a[i],a[j]);break;}}for(int j=i+1;j<=n;j++){ll d=a[j][i]*ksm(a[i][i],mod-2)%mod;for(int k=i;k<=n;k++) a[j][k]=(a[j][k]+mod-a[i][k]*d%mod)%mod;}}for(int i=1;i<=n;i++) ans=ans*a[i][i]%mod;return ans;
}
void work0(){for(int i=1;i<=m;i++){int x=read(),y=read(),w=read();if(x==y) continue;(a[x][x]+=w)%=mod;(a[y][y]+=w)%=mod;(a[x][y]+=mod-w)%=mod;(a[y][x]+=mod-w)%=mod;}printf("%lld\n",calc(n-1));
}
void work1(){for(int i=1;i<=m;i++){int x=read(),y=read(),w=read();if(x==y) continue;(a[y][y]+=w)%=mod;(a[x][y]+=mod-w)%=mod;}for(int i=1;i<n;i++){for(int j=1;j<n;j++) a[i][j]=a[i+1][j+1];}printf("%lld\n",calc(n-1));
}signed main(){
#ifndef ONLINE_JUDGE
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
#endifn=read();m=read();int op=read();if(op==0) work0();else work1();return 0;
}
/*
3
2 1 1
1 1
*/

带权图

如果一棵生成树的权值定义为边权乘积,直接把边理解成边权条1权边在对应的位置加边权即可。

如果一棵生成树的权值定义为边权加和,需要在矩阵内维护一个一次函数,最终在 modx2\mod x^2modx2 意义下求出的行列式的一次项就是答案。
因为这就相当于单独考虑一条边的边权,看它能加入多少棵生成树中。

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;const int N=35;
const int M=1050;
const int S=2e5+100;
const int inf=1e9;
const int mod=998244353;inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}int n,m;
int mx;
int prime[S],vis[S],tot;
ll mu[S];
void init(int n){mu[1]=1;for(int i=2;i<=n;i++){if(!vis[i]){prime[++tot]=i;mu[i]=-1;}for(int j=1;j<=tot&&prime[j]<=n/i;j++){int now=prime[j];vis[i*now]=1;if(i%now==0){mu[i*now]=0;break;}mu[i*now]=-mu[i];}}for(int i=1;i<=n;i++) mu[i]=(mu[i]+mod)%mod;return;
}struct node{ll a,b;
};
node operator + (const node x,const node y){return (node){(x.a+y.a)%mod,(x.b+y.b)%mod};}
node operator - (const node x,const node y){return (node){(x.a+mod-y.a)%mod,(x.b+mod-y.b)%mod};}
node operator * (const node x,const node y){return (node){(x.a*y.b+x.b*y.a)%mod,x.b*y.b%mod};}
node operator / (const node x,const node y){ll niv=ksm(y.b,mod-2);return (node){(x.a*y.b-x.b*y.a%mod+mod)%mod*niv%mod*niv%mod,x.b*niv%mod};
}
void operator += (node &x,const node y){x=x+y;}
void operator -= (node &x,const node y){x=x-y;}
void operator *= (node &x,const node y){x=x*y;}
void operator /= (node &x,const node y){x=x/y;}int u[M],v[M],w[M];
node a[N][N];
ll g[S],f[S];
void print(int n){puts("\n------\n");for(int i=1;i<=n;i++){for(int j=1;j<=n;j++) printf("(%lld %lld)  ",a[i][j].a,a[i][j].b);puts("");}
}
ll calc(int n){node ans=(node){0,1};for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){node d=a[j][i]/a[i][i];for(int k=i;k<=n;k++) a[j][k]-=(a[i][k]*d);}}for(int i=1;i<=n;i++){//printf("  i=%d a=%lld ans=%lld\n",i,a[i][i],ans[i])ans=ans*a[i][i];}return ans.a;
}
void work(int x){memset(a,0,sizeof(a));int cnt(0);for(int i=1;i<=m;i++){if(w[i]%x) continue;a[u[i]][u[i]]+=(node){w[i],1};a[v[i]][v[i]]+=(node){w[i],1};a[u[i]][v[i]]-=(node){w[i],1};a[v[i]][u[i]]-=(node){w[i],1};cnt++;}if(cnt<n-1) return;//printf("\n---x=%d\n",x);//print(n);g[x]=calc(n-1);//printf("ans=%lld\n",g[x]);return;
}signed main() {
#ifndef ONLINE_JUDGE
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
#endifn=read();m=read();for(int i=1;i<=m;i++){u[i]=read();v[i]=read();w[i]=read();mx=max(mx,w[i]);}init(mx);for(int x=1;x<=mx;x++) work(x);ll ans(0);for(int i=1;i<=mx;i++){for(int j=1;j*i<=mx;j++) (f[i]+=g[i*j]*mu[j])%=mod;(ans+=i*f[i])%=mod;}printf("%lld\n",ans);return 0;
}
/*
3
2 1 1
1 1
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316921.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P2016 战略游戏

P2016 战略游戏 题意&#xff1a; 他要建立一个古城堡&#xff0c;城堡中的路形成一棵无根树。他要在这棵树的结点上放置最少数目的士兵&#xff0c;使得这些士兵能了望到所有的路。 注意&#xff0c;某个士兵在一个结点上时&#xff0c;与该结点相连的所有边将都可以被了望…

.NET/C# 获取一个正在运行的进程的命令行参数

在自己的进程内部&#xff0c;我们可以通过 Main 函数传入的参数&#xff0c;也可以通过 Environment.GetCommandLineArgs 来获取命令行参数。但是&#xff0c;可以通过什么方式来获取另一个运行着的程序的命令行参数呢&#xff1f;进程内部获取传入参数的方法&#xff0c;可以…

CF896E Welcome home,Chtholly/[Ynoi2018]五彩斑斓的世界(并查集+第二分块)

CF896E Welcome home,Chtholly/[Ynoi2018]五彩斑斓的世界descriptionsolutioncodedescription 五彩斑斓的世界 CF896E Welcome home,Chtholly 五彩斑斓的世界是加强版&#xff0c;所以下面的题解部分是写的加强版 solution 第二分块 查询操作中把>x>x>x的数全都…

Defuse the Bombs Gym - 102822D

Defuse the Bombs Gym - 102822D 题目&#xff1a; 给你n个数&#xff0c;现在每轮会有三个操作&#xff1a; 1.选择一个数&#xff0c;使他加一 2.所有数减一 3.当有一个数变成负数时结束操作&#xff0c;否则回到第一步 问最多能进行几次第一步&#xff1f; 题解&#xff…

P4364 [九省联考 2018] IIIDX(线段树、贪心)

解析 感觉不至于黑的题。 然而我并不会做 did_idi​ 互不相同的时候直接无脑贪心即可&#xff0c;这样55分的好成绩就到手了。&#xff08;交完发现可以骗到60&#xff09; 滚榜级的良心分了属于是。 考虑有相同时如何做。 先把值降序排序&#xff0c;然后维护一棵线段树&…

CF1491H Yuezheng Ling and Dynamic Tree(分块)

CF1491H Yuezheng Ling and Dynamic Treedescriptionsolutioncodedescription 题目链接 solution 非常清新的小分块题了 前提&#xff1a;将序列分成n\sqrt{n}n​块&#xff0c;每块有n\sqrt{n}n​个数&#xff0c;记第iii个块的左右边界为Li,RiL_i,R_iLi​,Ri​&#xff0…

听说,霸都.NET技术社区准备搞线下聚会了?

.NET Core实战项目交流群日常交流嗨&#xff0c;你听说了没有&#xff1f;霸都.NET技术社区准备搞线下聚会了&#xff01;啥时候的事情啊&#xff1f;最近才知道的消息啊&#xff01;那你是从哪里知道的消息呢&#xff1f;.NET Core项目实战交流群&#xff08;637326624&#x…

Knowledge is Power Gym - 102822K

Knowledge is Power Gym - 102822K 题意&#xff1a; 给你一个数n&#xff0c;让你将n分解成一些互质的数&#xff0c;然后这些数的最大值减最小值要求最小&#xff0c;如果不行输出-1&#xff0c;否则输出最大值减最小值的最小情况 题解&#xff1a; 具体做法是通过枚举大…

P4383 [八省联考 2018] 林克卡特树(wqs二分、树形dp)

解析 它还真的不难。 乐。 这题没做出来有些谔谔。 外层wqs二分显而易见&#xff0c;里面不知道为啥我总觉得这个题可以贪心。 然后一直试图在原树直径上下功夫&#xff0c;一筹莫展。 看到题解“dp”两个字这题也就做完了… 就相当于要把一棵树分成若干条无交链&#xff0c;每…

ASP.NET Core中实现单体程序的事件发布/订阅 - LamondLu - 博客园

标题&#xff1a;ASP.NET Core中实现单体程序的事件发布/订阅作者&#xff1a;Lamond Lu地址&#xff1a;https://www.cnblogs.com/lwqlun/p/10468058.html项目源代码&#xff1a;https://github.com/lamondlu/EventHandlerInSingleApplication背景事件发布/订阅是一种非常强大…

CF1592E Bored Bakry(二进制+前缀异或和)

CF1592E Bored Bakrydescriptionsolutioncodedescription 题目链接 solution and\text{and}and如果第iii位为111&#xff0c;意味着区间内每个数的第iii位都是111 xor\text{xor}xor如果第iii位为111&#xff0c;意味着区间内有奇数个第iii位为111 这种涉及二进制操作的一般都…

Joy of Handcraft Gym - 102822J(线段树或差分)

Joy of Handcraft Gym - 102822J 题意&#xff1a; 每个灯有亮的周期和亮度&#xff0c;问1~m这段时间灯光最亮是多少 题解&#xff1a; 线段树维护区间最大值 根据灯的周期向这段区间加亮度k&#xff0c;然后利用线段树维护区间最大值 但是这样会超时&#xff0c;加个小优…

.NET Core 使用 HttpClient SSL 请求出错的解决办法

问题使用 HTTP Client 请求 HTTPS 的 API 时出现 The certificate cannot be verified up to a trusted certification authority 异常&#xff0c;并且证书已经传入。下面就是问题代码&#xff1a;public class Program{public static void Main(string[] args){var url &quo…

CF1580C Train Maintenance(分块)

CF1580C Train Maintenancedescriptionsolutioncodedescription 题目链接 solution 这是一种利用根号平衡时间复杂度的套路 分α\alphaα【操作参数】与n\sqrt{n}n​的关系&#xff0c;一半采取暴力&#xff0c;一半利用工具特殊处理 对于本题&#xff0c;假设第iii辆车的加…

P3746 [六省联考 2017] 组合数问题(倍增、dp)

解析 再次被“组合数问题”吊打qwq 和上一次不一样的是&#xff0c;这次更加被恶心到了。 一方面受上一个组合数问题影响&#xff0c;另外出题人也十分阴间&#xff0c;一开始还给了个组合数的公式&#xff0c;更加使我坚定的认为这是一道数学推柿子题。 然后就开始各种打表玩…

CF1473E Minimum Path(拆点+最短路)

CF1473E Minimum Pathdescriptionsolutioncodedescription 题目链接 solution 看到 ∑i1kwei\sum_{i1}^kw_{e_i}∑i1k​wei​​ 的式子&#xff0c;就应该联想到最短路 先考虑题目的弱化版&#xff0c;去掉 max,min\text{max},\text{min}max,min 的限制&#xff0c;变成一条…

2020CCPC绵阳

2020CCPC绵阳 题号题目名难度知识点AA Colorful GridBBuilding BlocksCCode a TrieDDefuse the Bombs签到二分EEscape from the IslandFFracture RayGGame of Cards银牌博弈论&#xff0c;SG函数HHide and SeekIInvaluable AssetsJJoy of Handcraft快铜线段树KKnowledge is Po…

P3747 [六省联考 2017] 相逢是问候(欧拉定理、线段树、光速幂)

解析 洛谷你恶事做尽&#xff01; 第三个tag在LOJ、bzoj等都是不需要的… 但在洛谷三只log根本过不去… 我谔谔。 如果做过 上帝与集合的正确用法 &#xff0c;那么本题就并不难了。 打个表就可以发现&#xff0c;不断取欧拉函数的上限只有log级别&#xff0c;这使得我们暴力…

Lottery Gym - 102822L

Lottery Gym - 102822L 题意&#xff1a; 有n个盒子&#xff0c;每个盒子有x个球&#xff0c;每个球的数值为2a,问最多能组成多少数&#xff1f;答案mod 1e97 题解&#xff1a; 二进制思维题&#xff0c;浓浓的cf风格 参考题解 我们将数按照幂次进行排序&#xff08;从小到…

[CCO 2019] Sirtet(差分约束+最短路)

[CCO 2019] Sirtetdescriptionsolutioncodedescription 题目链接 solution 很巧妙地将差分约束隐藏起来 问题的关键在于求出每一个sand停止运动的时间&#xff0c;这样很容易填涂出最后的答案&#xff08;向下平移即可&#xff09; 不妨设 ti,jt_{i,j}ti,j​ 表示 (i,j)(i…