考虑从小往大加边,然后把所有联通块的生成树个数计算出来。

然后把他们缩成一个点,继续添加下一组。

最后乘法原理即可。

写起来很恶心

  1. #include <queue>
  2. #include <cmath>
  3. #include <vector>
  4. #include <cstdio>
  5. #include <cstring>
  6. #include <iostream>
  7. #include <algorithm>
  8. using namespace std;
  9.  
  10. #define F(i,j,k) for (int i=j;i<=k;++i)
  11. #define D(i,j,k) for (int i=j;i>=k;--i)
  12. #define maxn 1005
  13. #define eps 1e-6
  14. const int md=31011;
  15. vector <int> v,to[maxn];
  16. queue <int> q;
  17. struct Edge{int u,v,w;}a[maxn];
  18. int n,m,fa[maxn];
  19. int b[maxn][maxn],inv[maxn];
  20. int vcnt,du[maxn],list[maxn],vis[maxn];
  21. bool cmp(Edge x,Edge y)
  22. {return x.w<y.w;}
  23. int gf(int k)
  24. {if (fa[k]==k) return k; else return fa[k]=gf(fa[k]);}
  25. int gauss(int n)
  26. {
  27. F(i,1,n) F(j,1,n) b[i][j]%=md;
  28. int ret=1;
  29. for (int i=1;i<n;++i)
  30. {
  31. for (int j=i+1;j<n;++j)
  32. while (b[j][i])
  33. {
  34. int t=b[i][i]/b[j][i];
  35. for (int k=i;k<n;++k)
  36. b[i][k]=(b[i][k]-b[j][k]*t+md)%md;
  37. for (int k=i;k<n;++k)
  38. swap(b[i][k],b[j][k]);
  39. ret=-ret;
  40. }
  41. if (b[i][i]==0) return 0;
  42. ret=ret*b[i][i]%md;
  43. }
  44. return abs((ret+md)%md);
  45. }
  46. int main()
  47. {
  48. scanf("%d%d",&n,&m);
  49. F(i,1,n) fa[i]=i;
  50. F(i,1,m){scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);}
  51. sort(a+1,a+m+1,cmp);
  52. int now=1,ans=1;
  53. while (now<=m)
  54. {
  55. int l=now,r=now;
  56. vcnt=0;
  57. memset(du,0,sizeof du);
  58. F(i,1,n) to[i].clear();
  59. while (a[r+1].w==a[r].w) r++;
  60. now=r+1;
  61. F(i,l,r)
  62. {
  63. int fl=gf(a[i].u),fr=gf(a[i].v);
  64. to[fl].push_back(fr);
  65. to[fr].push_back(fl);
  66. if (fl!=fr) du[fl]++,du[fr]++;
  67. }
  68. memset(vis,0,sizeof vis);
  69. F(i,1,n)
  70. if (du[i]&&!vis[i])
  71. {
  72. v.clear();
  73. memset(b,0,sizeof b);
  74. memset(inv,0,sizeof inv);
  75. q.push(i);inv[i]=1;vis[i]=1;
  76. while (!q.empty())
  77. {
  78. int x=q.front();v.push_back(x);q.pop();
  79. for (int j=0;j<to[x].size();++j)
  80. if (!vis[to[x][j]])
  81. q.push(to[x][j]),inv[to[x][j]]=1,vis[to[x][j]]=1;
  82. }
  83. for (int j=0;j<v.size();++j) list[v[j]]=j+1;
  84. for (int j=0;j<v.size();++j)
  85. for (int k=0;k<to[v[j]].size();++k)
  86. if (inv[to[v[j]][k]])
  87. {
  88. b[list[v[j]]][list[v[j]]]++,b[list[v[j]]][list[to[v[j]][k]]]--;
  89. }
  90. ans*=gauss(v.size());
  91. ans%=md;
  92. }
  93. F(i,l,r)
  94. {
  95. int fl=gf(a[i].u),fr=gf(a[i].v);
  96. if (fl!=fr){fa[fl]=fr;}
  97. }
  98. }
  99. int cnt=0;
  100. F(i,1,n) if (fa[i]==i)
  101. {
  102. cnt++;
  103. if (cnt==2) {printf("0\n"); return 0;}
  104. }
  105. printf("%d\n",ans);
  106. }

  

BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理的更多相关文章

  1. BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)

    题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...

  2. bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 就是缩点,每次相同权值的边构成的联通块求一下matrix tree.注意gauss里的 ...

  3. BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...

  4. [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】

    题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...

  5. [BZOJ]1016 JSOI2008 最小生成树计数

    最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...

  6. bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】

    有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...

  7. 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)

    1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...

  8. 1016: [JSOI2008]最小生成树计数

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 6200  Solved: 2518[Submit][St ...

  9. @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列

    目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...

随机推荐

  1. Glide图片框架

    //加载圆形图片Glide.with(this).load(WSCAppStatic.WEB_KEFU_PHOTO_URL+ "?usercode=8120000315") .as ...

  2. FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for Block pool <registering> (Datanode Uuid unassigned) service to controller/192.168.1.183:9000. Exiting. java.io.IOExcep

    2018-01-09 09:47:38,297 FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed ...

  3. Linux文件的IO操作 一

    系统调用 系统调用: 操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务 为什么用户程序不能直接访问系统内核提供的服务 为了更好地保护内核空间, ...

  4. Repbase library|divergence rate|self-sequence alignment|genomic rearrangement|cutoffs|breakpoint

    (Panda, dog and human repeat comparison):与其他动物比较重复序列 我们使用Repbase 库(重复序列库)+已知的转录原件序列+识别软件,评估出转录原件占比,并 ...

  5. 【转载】K-mer算法

    k-mer是指将reads分成包含k个碱基的字符串,一般长短为m的reads可以分成m-k+1个k-mers.举个例子吧,为了简化,有这么个reads(当然实际比这个长):AACTGACTGA.如果k ...

  6. Bootstrap历练实例:成功按钮

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  7. Protocol(协议)、Delegate(委托)、DataSource(数据源)

    这里以 UITableViewController 和 UITableView 的关系为例: //--------------------------------------------------- ...

  8. Codeforces Round #510 #C Array Product

    http://codeforces.com/contest/1042/problem/C 给你一个有n个元素序列,有两个操作:1,选取a[i]和a[j],删除a[i],将$a[i]*a[j]$赋值给a ...

  9. HDU - 4802 - GPA (水题)

    题意: 计算GPA,输入一个数字和一个字符串,用 数字×字符串对应的数值 思路: 用map对应数值,要注意的是字符串为P或者N的时候,不计入结果 代码: #include<iostream> ...

  10. 初涉树形dp

    算是一个……复习以及进阶? 什么是树形dp 树形dp是一种奇妙的dp…… 它的一个重要拓展是和各种树形的数据结构结合,比如说在trie上.自动机上的dp. 而且有些时候还可以拓展到环加外向树.仙人掌上 ...