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

Description

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

0<n,m<=2*10^4

Input

Output

Sample Input

5 6
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2

Sample Output

1
0
1

Solution

用rope实现可持久化数组,用rope的历史记录功能实现可持久化并查集,通过时间168ms

#include<cstdio>
#include<ext/rope>
#include<iostream>
using namespace std;
using namespace __gnu_cxx;
inline int Rin(){
  int x=0,c=getchar(),f=1;
  for(;c<48||c>57;c=getchar())
    if(!(c^45))f=-1;
  for(;c>47&&c<58;c=getchar())
    x=(x<<1)+(x<<3)+c-48;
  return x*f;
}
const int M=20010;
rope<int>*his[M];
int n,m,a[M];
inline int find(int i,int x){
  int d=x,p;
  while(his[i]->at(x)^x)x=his[i]->at(x);
  while(d^x)p=his[i]->at(d),his[i]->replace(d,x),d=p;
  return x;
}
inline void merge(int i,int x,int y){
  x=find(i,x),y=find(i,y);
  if(x^y)
    his[i]->replace(y,x);
}
int main(){
  n=Rin(),m=Rin();
  for(int i=1;i<=n;i++)a[i]=i;
  his[0]=new rope<int>(a,a+1+n);
  for(int i=1,x,y,sign;i<=m;i++){
    his[i]=new rope<int>(*his[i-1]);
    scanf("%d",&sign);
    switch(sign){
    case 1:
      x=Rin(),y=Rin();
      merge(i,x,y);
      break;
    case 2:
      x=Rin();
      his[i]=his[x];
      break;
    case 3:
      x=Rin(),y=Rin();
      printf("%d\n",(!(find(i,x)^find(i,y))));
      break;
    }
  }
  return 0;
}
时间: 2024-08-10 19:09:13

[bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)的相关文章

bzoj3673可持久化并查集 by zky&amp;&amp;bzoj3674可持久化并查集加强版

bzoj3673可持久化并查集 by zky 题意: 维护可以恢复到第k次操作后的并查集. 题解: 用可持久化线段树维护并查集的fa数组和秩(在并查集里的深度),不能路径压缩所以用按秩启发式合并,可以使合并均摊复杂度为O(nlog2n).可持久化线段树实际上就是在更新节点时按主席树的插入方式新建一条路径(其实主席树就是可持久化权值线段树). 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

【BZOJ3673】【可持久化并查集】可持久化并查集 by zky

Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6 1 1 2 3 1 2 2 0 3 1 2 2 1 3 1 2 Sample Output 1 0 1 HINT Source 出题人大S [分析] 出题人给我滚出来!保证不打死你! 真是***了,你题意描述清楚点会死啊.

【可持久化数组】【rope】bzoj3673 bzoj3674 可持久化并查集 by zky

rope教程:http://blog.csdn.net/iamzky/article/details/38348653 Code(bzoj3673): 1 #include<cstdio> 2 #include<ext/rope> 3 using namespace std; 4 using namespace __gnu_cxx; 5 rope<int> *fa[20001]; 6 int a,b,n,m,A[20001],op; 7 int Root(int num

BZOJ 3673: 可持久化并查集 by zky

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2084  Solved: 941[Submit][Status][Discuss] Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6

[BZOJ3674]可持久化并查集加强版&amp;[BZOJ3673]可持久化并查集 by zky

思路: 用主席树维护并查集森林,每次连接时新增结点. 似乎并不需要启发式合并,我随随便便写了一个就跑到了3674第一页?3673是这题的弱化版,本来写个暴力就能过,现在借用加强版的代码(去掉异或),直接吊打暴力程序. 1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 register char ch; 5 while(!isdigit(ch=getchar())); 6 register int x=ch

【BZOJ 3674】可持久化并查集加强版&amp;【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之

最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破之. 3:输出判断即可. 难者不会,会者不难,1h前我还在膜这道题,现在吗hhh就当支持下zky学长出的题了. 3673: #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=ge

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

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 http://www.lydsy.com/JudgeOnline/problem.php?id=3673 双倍经验啦啦啦.. 给主席树换了个名称果然高大上... 首先要可持久化并查集其实就是可持久化数组... 那么因为数组的形式是这样的$P[x]$,那么我们用一种数据结构实现查找x返回对应的$P[x]$即可啦啦啦. 然后那么我所学的可持久化目前只有主席树QAQ哪天去写写fhqtreap...

BZOJ 3673 可持久化并查集 by zky &amp;&amp; 3674 可持久化并查集加强版

题目大意:维护一种数据结构实现可持久化并查集. 思路:利用可持久化线段树实现可持久化数组维护可持久化并查集.(不知道3674哪里加强了... CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define RANGE 8000010 #define MAX 200200 using namespace std; struct SegTree

BZOJ 3673 可持久化并查集 by zky 可持久化并查集

题目大意:给定n个集合,提供三种操作: 1.合并a,b所在集合 2.回到第k次操作之后的状态 3.询问a,b是否在同一集合 可持久化并查集0.0 实现方式是用可持久化线段树实现可持久化数组维护可持久化并查集... 至于可持久化数组,每条路径上只有叶节点的位置的num域是有意义的,感觉无比浪费0.0 可是不这样还真没法维护0.0 合并时本来应该按照每个节点的深度之和维护,结果手残懒得写,只用siz维护了0.0 至于路径压缩,写了比不写慢0.0 还是不写了吧 #include<cstdio> #i