点开这题纯属无聊……不过既然写掉了,那就丢一个模板好了

不得不说,可持久化并查集实现真的很暴力,就是把并查集的数组弄一个主席树可持久化。

有一点要注意的是不能写路径压缩,这样跳版本的时候会错,所以弄一个按秩合并来降低时间复杂度。

总时间复杂度$O(nlog^2n)$。

听说用siz实现按秩合并会比较好,因为这样还能查询集合大小,有时间以后补上。

Code:

  1. #include <cstdio>
  2. using namespace std;
  3.  
  4. const int N = 1e5 + ;
  5. const int M = 2e5 + ;
  6.  
  7. int n, qn;
  8.  
  9. inline void read(int &X) {
  10. X = ;
  11. char ch = ;
  12. int op = ;
  13. for(; ch > ''|| ch < ''; ch = getchar())
  14. if(ch == '-') op = -;
  15. for(; ch >= '' && ch <= ''; ch = getchar())
  16. X = (X << ) + (X << ) + ch - ;
  17. X *= op;
  18. }
  19.  
  20. struct Node {
  21. int lc, rc, dep, fa;
  22. };
  23.  
  24. namespace PUfs {
  25. Node s[N * ];
  26. int root[M * ], nodeCnt;
  27.  
  28. #define mid ((l + r) >> 1)
  29.  
  30. void build(int &p, int l, int r) {
  31. p = ++nodeCnt;
  32. if(l == r) {
  33. s[p].fa = l;
  34. return;
  35. }
  36.  
  37. build(s[p].lc, l, mid);
  38. build(s[p].rc, mid + , r);
  39. }
  40.  
  41. void modify(int &p, int l, int r, int x, int f, int pre) {
  42. p = ++nodeCnt;
  43. if(l == r) {
  44. s[p].fa = f;
  45. s[p].dep = s[pre].dep;
  46. return;
  47. }
  48.  
  49. s[p].lc = s[pre].lc, s[p].rc = s[pre].rc;
  50. if(x <= mid) modify(s[p].lc, l, mid, x, f, s[pre].lc);
  51. else modify(s[p].rc, mid + , r, x, f, s[pre].rc);
  52. }
  53.  
  54. void add(int p, int l, int r, int x) {
  55. if(l == r) {
  56. s[p].dep++;
  57. return;
  58. }
  59. if(x <= mid) add(s[p].lc, l, mid, x);
  60. else add(s[p].rc, mid + , r, x);
  61. }
  62.  
  63. int query(int p, int l, int r, int x) {
  64. if(l == r) return p;
  65.  
  66. if(x <= mid) return query(s[p].lc, l, mid, x);
  67. else return query(s[p].rc, mid + , r, x);
  68. }
  69.  
  70. int find(int now, int x) {
  71. int f = query(now, , n, x);
  72. if(s[f].fa == x) return f;
  73. return find(now, s[f].fa);
  74. }
  75.  
  76. } using namespace PUfs;
  77.  
  78. inline void print(int p) {
  79. printf("%d: ", p);
  80. for(int j = ; j <= n; j++)
  81. printf("%d ", s[find(root[p], j)].fa);
  82. /* for(int j = 1; j <= n; j++)
  83. printf("%d ", query(root[p], 1, n, j)); */
  84. printf("\n");
  85. }
  86.  
  87. inline void swap(int &x, int &y) {
  88. int t = x;
  89. x = y;
  90. y = t;
  91. }
  92.  
  93. int main() {
  94. read(n), read(qn);
  95.  
  96. nodeCnt = ;
  97. build(root[], , n);
  98.  
  99. // print(0);
  100.  
  101. for(int op, i = ; i <= qn; i++) {
  102. read(op);
  103. if(op == ) {
  104. root[i] = root[i - ];
  105. int x, y;
  106. read(x), read(y);
  107. int fx = find(root[i], x), fy = find(root[i], y);
  108. if(s[fx].fa == s[fy].fa) continue;
  109. if(s[fx].dep > s[fy].dep) swap(fx, fy);
  110. modify(root[i], , n, s[fx].fa, s[fy].fa, root[i - ]);
  111. if(s[fx].dep == s[fy].dep) add(root[i], , n, s[fy].fa);
  112. }
  113. if(op == ) {
  114. int k;
  115. read(k);
  116. root[i] = root[k];
  117. }
  118. if(op == ) {
  119. root[i] = root[i - ];
  120. int x, y;
  121. read(x), read(y);
  122. int fx = find(root[i], x), fy = find(root[i], y);
  123. if(s[fx].fa == s[fy].fa) puts("");
  124. else puts("");
  125. }
  126. // print(i);
  127. }
  128.  
  129. return ;
  130. }

Luogu 3402 可持久化并查集的更多相关文章

  1. 洛谷P4768 [NOI2018]归程 [可持久化并查集,Dijkstra]

    题目传送门 归程 格式难调,题面就不放了. 分析: 之前同步赛的时候反正就一脸懵逼,然后场场暴力大战,现在呢,还是不会$Kruskal$重构树,于是就拿可持久化并查集做. 但是之前做可持久化并查集的时 ...

  2. 洛谷P3402 【模板】可持久化并查集 [主席树,并查集]

    题目传送门 可持久化并查集 n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 ...

  3. bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集

    题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673 bzoj3674:https://www.lydsy.com/Jud ...

  4. 带撤销并查集 & 可持久化并查集

    带撤销并查集支持从某个元素从原来的集合中撤出来,然后加入到一个另外一个集合中,或者删除该元素 用一个映射来表示元素和并查集中序号的关系,代码中用\(to[x]\) 表示x号元素在并查集中的 id 删除 ...

  5. [bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)

    Description n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0& ...

  6. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

  7. bzoj3674 可持久化并查集

    我是萌萌的任意门 可持久化并查集的模板题-- 做法好像很多,可以标号法,可以森林法. 本来有O(mloglogn)的神算法(按秩合并+倍增),然而我这种鶸渣就只会写O(mlog2n)的民科算法--再加 ...

  8. 【BZOJ3673】&&【BZOJ3674】: 可持久化并查集 by zky 可持久化线段树

    没什么好说的. 可持久化线段树,叶子节点存放父亲信息,注意可以规定编号小的为父亲. Q:不是很清楚空间开多大,每次询问父亲操作后修改的节点个数是不确定的.. #include<bits/stdc ...

  9. 【BZOJ】3673: 可持久化并查集 by zky & 3674: 可持久化并查集加强版(可持久化线段树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3674 http://www.lydsy.com/JudgeOnline/problem.php?id ...

随机推荐

  1. Nhibernate系列学习之(五) 存储过程

    NHibernate也是能够操作存储过程的,不过第一次配置可能会碰到很多错误. 一.删除 首先,我们新建一个存储过程如下: CREATE PROC DeletePerson @Id int AS DE ...

  2. InnoDB引擎的特点及优化方法

    1.什么是InnoDB引擎?      InnoDB引擎是MySQL数据库的另一个重要的存储引擎,正成为目前MySQL AB所发行的新版的标准,被包含在所有二进制安装包里,和其他存储引擎相比,Inno ...

  3. Chrome MarkDown Preview Plus

    /************************************************************************** * Chrome MarkDown Previe ...

  4. RabbitMQ 权限分离&HA操作文档

    概要 默认情况下,使用帐号guest帐号登陆MQ,所有用户的queue信息,全部创建在根目录/的virtual host下,而这样,就会导致,任一用户登录后,都能看到其他用户的queue信息. 针对以 ...

  5. C++对C语言的拓展(5)—— 函数重载和函数指针结合

    1.函数指针的介绍 函数指针指向某种特定类型,函数的类型由其参数及返回类型共同决定,与函数名无关.举例如下: int add(int nLeft,int nRight);//函数定义 该函数类型为in ...

  6. javascript switch continue break 执行语句

    1:switch 关键字段:switch(n).case.break.default switch(n) :n是一个表达式 或者是一变量,用来与其下的各种case进行匹配,比如:此时的day输出的是 ...

  7. /etc删了怎么办

    实施一个哥们一个手抖,把/etc删掉了:别人无法ssh到上面,除了他.怎么办? 从类似的OK机器中打包一个etc.tar,然后将etc.tar放到OK机器www服务器目录里面:然后在问题机器上面通过w ...

  8. 洛谷【P1439】【模板】最长公共上升子序列

    浅谈\(DP\):https://www.cnblogs.com/AKMer/p/10437525.html 题目传送门:https://www.luogu.org/problemnew/show/P ...

  9. 转载:trap 的用法 /etc/init.d/rcS trap :1 2 3 24

    在有些情况下,我们不希望自己的shell脚本在运行时刻被中断,比如说我们写得shell脚 本设为某一用户的默认shell,使这一用户进入系统后只能作某一项工作,如数据库备份, 我 们可不希望用户使用c ...

  10. oracle的自增长

    mysql的自增长非常容易,一个 AUTO_INCREMENT 就搞定,可是oracle就不行了 下面是oracle的自增长 #创建一个表CREATE TABLE T_TEST_DEPARTMENTS ...