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

3673: 可持久化并查集 by zky

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 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
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2

Sample Output

1
0
1

HINT

Source

出题人大SB

分析:

因为我们需要回溯到历史版本所以需要把并查集可持久化,所以我们用可持久化线段树维护一个可持久化的数组,支持单点修改单点查询...数组中维护的是fa和siz...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=20000+5,maxm=5000000+5;

int n,m,tot,ls[maxm],rs[maxm],fa[maxm],siz[maxm],root[maxn];

inline void build(int &x,int l,int r){
	x=++tot;int mid=(l+r)>>1;
	if(l==r){
		siz[x]=1,fa[x]=l;
		return;
	}
	build(ls[x],l,mid);build(rs[x],mid+1,r);
}

inline void change(int l,int r,int x,int &y,int pos,int val){
	y=++tot;
	if(l==r){
		fa[y]=val,siz[y]=siz[x];
		return;
	}
	int mid=(l+r)>>1;ls[y]=ls[x];rs[y]=rs[x];
	if(pos<=mid)
		return change(l,mid,ls[x],ls[y],pos,val);
	else
		return change(mid+1,r,rs[x],rs[y],pos,val);
}

inline void add(int l,int r,int x,int pos,int val){
	if(l==r){
		siz[x]+=val;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)
		add(l,mid,ls[x],pos,val);
	else
		add(mid+1,r,rs[x],pos,val);
}

inline int query(int l,int r,int x,int pos){
	if(l==r)
		return x;
	int mid=(l+r)>>1;
	if(pos<=mid)
		return query(l,mid,ls[x],pos);
	else
		return query(mid+1,r,rs[x],pos);
}

inline int find(int rt,int x){
	int f=query(1,n,rt,x);
	if(fa[f]==x)
		return f;
	return find(rt,fa[f]);
}

signed main(void){
	scanf("%d%d",&n,&m);build(root[0],1,n);
	for(int i=1,opt,x,y;i<=m;i++){
		scanf("%d",&opt);
		if(opt==1){
			scanf("%d%d",&x,&y);root[i]=root[i-1];
			int fx=find(root[i],x),fy=find(root[i],y);
			if(fa[fx]==fa[fy])
				continue;
			if(siz[fx]>siz[fy])
				swap(fx,fy);
			change(1,n,root[i-1],root[i],fa[fx],fa[fy]),add(1,n,root[i],fa[fy],siz[fx]);
		}
		else if(opt==2)
			scanf("%d",&x),root[i]=root[x];
		else{
			scanf("%d%d",&x,&y),root[i]=root[i-1];
			int fx=find(root[i],x),fy=find(root[i],y);
			if(fa[fx]==fa[fy])
				puts("1");
			else
				puts("0");
		}
	}
	return 0;
}

  



By NeighThorn

时间: 2024-08-27 03:42:05

BZOJ 3673: 可持久化并查集 by zky的相关文章

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

【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 可持久化并查集

本质上是维护两个可持久化数组,用可持久化线段树维护. 1 /************************************************************** 2 Problem: 3673 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:76 ms 7 Memory:13780 kb 8 **********************************************************

3673: 可持久化并查集 by zky

Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2724  Solved: 1206[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 1 1 2 3 1 2 2 0 3 1

BZOJ 3674 可持久化并查集加强版(主席树变形)

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 2515  Solved: 1107 [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 Inp

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

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

BZOJ 3674: 可持久化并查集加强版

3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 2605  Solved: 977[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:…… n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状

[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