可持久化并查集的两种实现

对于像UVA 11987 Almost Union-Find这样的题目,要求把一个元素从一个集合中剥离的情况,我们只需要新建一个节点然后……….

还是看代码吧:

inline void move(int x,int y)     // 把x从y集合中剥离
{
    int fx = find(id[x]),fy = find(id[y]);
    if(fx == fy)  return ;
    cnt[fx] --,sum[fx] -= x;
    id[x] = ++ tot;		// 可持久化
    f[id[x]] = fy;  cnt[fy] ++,sum[fy] += x;
}

这种方法主要是利用id[],在最初时id[i] = i,随着移动i,id[i]也在变化,在访问i时,我们需直接用id[i]代替。

对于 BZOJ  3674: 可持久化并查集加强版 我们就不能cheat 了,我们需要真的可持久化了。

因为并查集的所有信息都保存在fa[]里,所以,我们只需要用可持久化线段树实现一个可持久化数组就可以了。

ACCode:

#include<cstdio>
#include<iostream>
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();
    while(ch>‘9‘||ch<‘0‘)ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x;
}
int n,m,sz,last;
int root[200005],ls[10000005],rs[10000005],v[10000005],deep[10000005];
void build(int &k,int l,int r)
{
	if(!k)k=++sz;
	if(l==r){v[k]=l;return;}
	int mid=(l+r)>>1;
	build(ls[k],l,mid);
	build(rs[k],mid+1,r);
}
void modify(int l,int r,int x,int &y,int pos,int val)
{
	y=++sz;
	if(l==r){v[y]=val;return;}
	ls[y]=ls[x];rs[y]=rs[x];
	int mid=(l+r)>>1;
	if(pos<=mid)
		modify(l,mid,ls[x],ls[y],pos,val);
	else modify(mid+1,r,rs[x],rs[y],pos,val);
}
int query(int k,int l,int r,int pos)
{
	if(l==r)return k;
	int mid=(l+r)>>1;
	if(pos<=mid)return query(ls[k],l,mid,pos);
	else return query(rs[k],mid+1,r,pos);
}
void add(int k,int l,int r,int pos)
{
	if(l==r){deep[k]++;return;}
	int mid=(l+r)>>1;
	if(pos<=mid)add(ls[k],l,mid,pos);
	else add(rs[k],mid+1,r,pos);
}
int find(int k,int x)
{
    int p=query(k,1,n,x);
	if(x==v[p])return p;
    return find(k,v[p]);
}
int main()
{
	n=read();m=read();
	build(root[0],1,n);
	int f,k,a,b;
	for(int i=1;i<=m;i++)
	{
		f=read();
		if(f==1)
		{
			root[i]=root[i-1];
			a=read();b=read();a=a^last;b=b^last;
			int p=find(root[i],a),q=find(root[i],b);
			if(v[p]==v[q])continue;
			if(deep[p]>deep[q])swap(p,q);
			modify(1,n,root[i-1],root[i],v[p],v[q]);
			if(deep[p]==deep[q])add(root[i],1,n,v[q]);
		}
		if(f==2)
		{k=read();k=k^last;root[i]=root[k];}
		if(f==3)
		{
			root[i]=root[i-1];
			a=read();b=read();a=a^last;b=b^last;
		    int p=find(root[i],a),q=find(root[i],b);
			if(v[p]==v[q])last=1;
			else last=0;
			printf("%d\n",last);
		}
	}
	return 0;
}

可持久化并查集的两种实现

时间: 2024-08-13 22:05:20

可持久化并查集的两种实现的相关文章

食物链 POJ - 1182 (并查集的两种写法)

这是一个非常经典的带权并查集,有两种写法. 1 边权并查集 规定一下,当x和y这条边的权值为0时,表示x和y是同类,当为1时,表示x吃y,当为2时,表示x被y吃. 一共有三种状态,如图,当A吃B,B吃C时,C必须吃A,路径压缩后,A被C吃. 然后就是带权并查集的模板了. 判断条件,当x和y在同一颗树上是, 如果说,x和y之间的关系是0,那么x和RA与Y和RA之间的关系必须相同才行.x和Y之间的关系是1,当S[y]=2时,S[x]=1,当s[y]=1时,s[x]应等于0,才能满足 所以判断条件为(

并查集的两种实现(按秩合并+路径压缩)

并查集:就是有求并集,查找元素属于哪个集合的功能. 1.路径压缩:使X到根上的每一个节点的父节点都变为根节点. 查询: void Find(int x) { if(a[x]==0) return x; else return a[x]=Find(a[x]); } 合并: void Merge(int x,int y) { int t1=Find(x),t2=Find(y); if(t1!=t2) a[t1]=t2; } 2.按秩合并:使较浅的树成为较深的树的子树. 查询: void Find(i

可持久化并查集总结

可持久化并查集总结 标签: 数据结构--可持久化--可持久化并查集 阅读体验:https://www.zybuluo.com/Junlier/note/1268670 前面的话 其实看起来很高大上,最后还不是沦为被我这种菜鸡都能学会的东西 嗯,我只是想解释这个并不是很难...连我这么弱都... 然后还是以模板题为背景将比较好...洛谷题目传送门 实现方法 其实可持久化并查集就是要支持回到以前的版本(类比可持久化$数组/线段树$之类的) 那么我都类比了,很显然就是用主席树来维护吧 主席树部分 我们

半可持久化并查集

对于常见的可持久化并查集, 我们可以通过 按秩合并 + 可持久化数组 . 但是, 此半可持久化并查集, 非彼可持久化并查集. 我们不用支持时间旅行, 即不用支持回到过去的某个版本, 而只用储存历史信息. 举个例子来说吧. n 个点, 支持两种操作: ① 将某两个点之间连边; ② 查询在前 t 次操作下, 某两个点是否连通. 强制在线. 核心模型 给定 n 个点, m 条带权边的无向图. 求在所有边权不超过 d 的边的作用下, 某个点或某两个点的连通性信息. 强制在线. 之前举的那个例子也可以这样

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

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 3225  Solved: 1192[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后--hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可

【BZOJ3674】可持久化并查集加强版

可持久化并查集我觉得就是可持久化数组的一种应用.可持久化数组,顾名思义,就是有历史版本的数组,那么如果我们暴力修改储存的话,修改O(n)查询O(1),空间O(n*m),这样肯定不可行,那么我们发现主席树有这样的功能,他可以快速复制,修改O(log),查询O(log),空间(m*log),是一个可行的方案.然后我们可持久化f数组维护fa,每次按照深度启发式合并,不进行路径压缩,这样能保证时间复杂度位单次O(log^2),空间复杂度为O(2*n+m*log).我不知道为什么不路径压缩,路径压缩是完全

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

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[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

【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