tarjan有向图缩点的基础应用。把原图中某点的连通数转化为反向图中”能够到达某点的个数“。缩点后,每个新点的贡献等于

  原dcc大小 * f[i]

  其中f[i]表示(包括该点自身)通向该点的点的个数。设u点为v的入度,满足转移方程:

    

  所以我们按照拓扑序dp求解即可。f[i]的初值设为该分量的节点数。

  这个题引出一个很重要的想法:如何避免两个强连通分量缩点时连有重边?对于2000的数据范围,一个二维布尔数组完全可以承受,但显然有更普适的优秀做法,这就是Hash。去重边实际上是二元组的判重问题,我们只需要一个合适的“进位”技术,就可以保证任意两个二元组所映射的键值是绝不相同的。如果key值太大,就要套用Hash表解决了。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <queue>
  5. #include <cctype>
  6. #define maxn 2010
  7. using namespace std;
  8. template <typename T>
  9. void read(T &x) {
  10. x = 0;
  11. char ch = getchar();
  12. while (!isdigit(ch))
  13. ch = getchar();
  14. while (isdigit(ch))
  15. x = x * 10 + (ch ^ 48),
  16. ch = getchar();
  17. return;
  18. }
  19. struct E {
  20. int to, nxt;
  21. } edge[maxn * maxn], edge2[maxn * maxn];
  22. int n, head[maxn], top, head2[maxn], top2;
  23. inline void insert(int u, int v) {
  24. edge[++top] = (E) {v, head[u]};
  25. head[u] = top;
  26. }
  27. inline void insert2(int u, int v) {
  28. edge2[++top2] = (E) {v, head2[u]};
  29. head2[u] = top2;
  30. }
  31. int dfn[maxn], low[maxn], timer,
  32. sta[maxn], stp,
  33. c[maxn], cnt,
  34. w[maxn];
  35. bool ins[maxn];
  36. void tarjan_dfs(int u) {
  37. dfn[u] = low[u] = ++timer;
  38. sta[++stp] = u, ins[u] = true;
  39. for (int i = head[u]; i; i = edge[i].nxt) {
  40. int v = edge[i].to;
  41. if (!dfn[v])
  42. tarjan_dfs(v), low[u] = min(low[u], low[v]);
  43. else if (ins[v])
  44. low[u] = min(low[u], dfn[v]);
  45. }
  46. if (dfn[u] == low[u]) {
  47. ++cnt;
  48. int x;
  49. do {
  50. x = sta[stp--];
  51. ins[x] = false;
  52. c[x] = cnt;
  53. ++w[cnt];
  54. } while (x != u);
  55. }
  56. }
  57. void tarjan() {
  58. for (int i = 1; i <= n; ++i)
  59. if (!dfn[i]) tarjan_dfs(i);
  60. }
  61. namespace Hash_table {
  62. //  const int Size(23333309), step = 7;//空间足够,不用取模
  63. bool tb[4004001];
  64. inline int H (int u, int v) {
  65. return u * 2001 + v;
  66. }
  67. bool Hash(int u, int v) {
  68. int key = H(u, v);
  69. if (tb[key]) return false;
  70. tb[key] = true;
  71. return true;
  72. }
  73. } using namespace Hash_table;
  74. int ind[maxn];
  75. //bool done[maxn][maxn];//Hash更为优秀
  76. void build() {
  77. for (int u = 1; u <= n; ++u)
  78. for (int i = head[u]; i; i = edge[i].nxt) {
  79. int v = edge[i].to;
  80. if (c[u] != c[v] && Hash(c[u], c[v])) {
  81. insert2(c[u], c[v]);
  82. ++ind[c[v]];
  83. }
  84. }
  85. }
  86. long long sum = 0;
  87. long long f[maxn];
  88. queue<int> que;
  89. void dp() {
  90. for (int i = 1; i <= cnt; ++i) {
  91. f[i] = w[i];
  92. if (!ind[i]) {
  93. sum += w[i] * w[i];
  94. que.push(i);
  95. }
  96. }
  97. while (!que.empty()) {
  98. int u = que.front(); que.pop();
  99. for (int i = head2[u]; i; i = edge2[i].nxt) {
  100. int v = edge2[i].to;
  101. f[v] += f[u];
  102. --ind[v];
  103. if (!ind[v]) {
  104. sum += w[v] * f[v];
  105. que.push(v);
  106. }
  107. }
  108. }
  109. }
  110. int main() {
  111. read(n);
  112. for (int u = 1; u <= n; ++u)
  113. for (int v = 1; v <= n; ++v) {
  114. char ch = getchar();
  115. while (!isdigit(ch)) ch = getchar();
  116. if (ch == '1') insert(v, u);//反向存图
  117. }
  118. tarjan();
  119. build();
  120. dp();
  121. printf("%lld", sum);
  122. return 0;
  123. }

Luogu P4306 JSOI2010 连通数的更多相关文章

  1. Luogu P4306 [JSOI2010]连通数 传递闭包

    正解其实是\(Tarjan\) + \(拓扑拓扑\),但是却可以被\(O(N^3 / 32)\)复杂度的传递闭包水过去.心疼一下写拓扑的小可爱们. 学到一个\(bitset\)优化布尔图的骚操作,直接 ...

  2. P4306 [JSOI2010]连通数

    思路 要求求每个点能到达的点数就是传递闭包 然后n^3Floyd可做,但是n=2000,然后bitset压位 复杂度\(O(\frac{n^3}{32})\),能过 代码 #include <c ...

  3. BZOJ 2208: [Jsoi2010]连通数 tarjan bitset

    2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  4. bzoj2208:[Jsoi2010]连通数

    http://blog.csdn.net/u013598409/article/details/47037499 里面似乎有生成数据的... //我本来的想法是tarjan缩点之后然后将图遍历一遍就可 ...

  5. bzoj2208 [Jsoi2010]连通数(scc+bitset)

    2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1879  Solved: 778[Submit][Status ...

  6. BZOJ 2208: [Jsoi2010]连通数( DFS )

    n只有2000,直接DFS就可以过了... -------------------------------------------------------------------------- #in ...

  7. 2208: [Jsoi2010]连通数

    2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1371  Solved: 557[Submit][Status ...

  8. bzoj 2208 [Jsoi2010]连通数

    2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 输入数据第一行是图顶点的数量,一个正整数N ...

  9. 【BZOJ2208】[JSOI2010]连通数(Tarjan)

    [BZOJ2208][JSOI2010]连通数(Tarjan) 题面 BZOJ 洛谷 题解 先吐槽辣鸡洛谷数据,我写了个\(O(nm)\)的都过了. #include<iostream> ...

随机推荐

  1. java数据结构-09双端队列

    一.相关概念: (Deque)双端队列能够在队头.队尾进行添加.删除等操作  二.接口设计:  三.代码实现 public class Deque<E> { private List< ...

  2. Docker composer搭建Spring Cloud Alibaba 运行环境(二)

    " Spring Cloud Alibaba要用到的组件很多,注册中心nacos, 限流sentinel, 数据库,网关等等.由于用到的组件相对较多,部署会很繁琐,最关键的是没有资源服务器, ...

  3. 使用 tabindex 配合 focus-within 巧妙实现父选择器

    本文将介绍一个不太实用的小技巧,使用 tabindex 配合 :focus-within 巧妙实现父选择器. CSS 中是否存在父选择器? 这是一个非常经典的问题,到目前为止,CSS 没有真正意义上被 ...

  4. 一次 KVM 虚拟机磁盘占满的排查过程

    一次 KVM 虚拟机磁盘占满的排查过程 KVM 虚拟机系统为 CentOS,文件系统为 XFS. 现象如下: 使用 df -h 命令发现磁盘剩余空间为30k(总大小为30G),使用 df -i 发现 ...

  5. drf JWT认证模块与自定制

    JWT模块 在djangorestframework中,有一款扩展模块可用于做JWT认证,使用如下命令进行安装: pip install djangorestframework-jwt 现在,就让我们 ...

  6. 关于C中指针的引用,解引用与脱去解引用

    *,& 在指针操作中的意义 (1)* 大家都知道在写int *p 时,*可以声明一个指针.很少人知道*在C/C++中还有一个名字就是"解引用".他的意思就是解释引用,说的通 ...

  7. OJ-1:时钟问题【九度1553】

    题目描述: 如图,给定任意时刻,求时针和分针的夹角(劣弧所对应的角). 输入: 输入包含多组测试数据,每组测试数据由一个按hh:mm表示的时刻组成. 输出: 对于每组测试数据,输出一个浮点数,代表时针 ...

  8. Sentinel 的一些小扩展

    随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制.熔断降级.系统自适应保护等多个维度来帮助您保障微服务的稳定 ...

  9. 优测 x QTA 兼容性测试全面启动啦

    鉴于Android系统开放性开发,以及Android系统在智能机市场的覆盖率超高的特点,APP的兼容性测试需求大幅提升.为迎合市场需求,优测(Utest)与QTA合作,全力打造兼容性测试服务.由优测提 ...

  10. Spring源码之Bean生命周期

    https://www.jianshu.com/p/1dec08d290c1 https://www.cnblogs.com/zrtqsk/p/3735273.html 总结 将class文件加载成B ...