• 【BZOJ3673/3674】可持久化并查集/可持久化并查集加强版 可持久化线段树


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

    Description

    Description:
    自从zkysb出了可持久化并查集后……
    hzwer:乱写能AC,暴力踩标程
    KuribohG:我不路径压缩就过了!
    ndsf:暴力就可以轻松虐!
    zky:……
    n个集合 m个操作
    操作:
    1 a b 合并a,b所在集合
    2 k 回到第k次操作之后的状态(查询算作操作)
    3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
    请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0
    0<n,m<=2*10^5

    Input

    Output

    Sample Input

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

    Sample Output

    1
    0
    1

    题解:要实现可持久化并查集,只需实现可持久化数组,要实现可持久化数组,只能用可持久化线段树QAQ

    具体方法是,让可持久化线段树的叶子节点储存并查集的fa,siz信息,然后每次查询,更新都在可持久化线段树上完成。回到之前的状态只需要调用之前的树根就行了。此外不用路径压缩。

    bz3674:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=200010;
    struct sag
    {
    	int ls,rs,siz,fa;
    }s[maxn*50];
    int n,m,tot,now,ans;
    int rt[maxn<<1],to[maxn];
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void insert(int x,int &y,int l,int r,int pos,int a,int b)
    {
    	if(pos>r)	return ;
    	y=++tot;
    	if(l==r)
    	{
    		s[y].siz=a,s[y].fa=b;
    		return ;
    	}
    	int mid=l+r>>1;
    	if(pos<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,pos,a,b);
    	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,pos,a,b);
    }
    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,s[x].ls,pos);
    	else	return query(mid+1,r,s[x].rs,pos);
    }
    void build(int l,int r,int &x)
    {
    	x=++tot;
    	if(l==r)
    	{
    		s[x].fa=l,s[x].siz=1;
    		return ;
    	}
    	int mid=l+r>>1;
    	build(l,mid,s[x].ls),build(mid+1,r,s[x].rs);
    }
    int find(int x)
    {
    	int fx;
    	while(1)
    	{
    		fx=query(1,n,rt[now],x);
    		if(s[fx].fa!=x)	x=s[fx].fa;
    		else	break;
    	}
    	return fx;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,j,a,b,c,ra,rb;
    	build(1,n,rt[0]);
    	for(i=1;i<=m;i++)
    	{
    		c=rd();
    		if(c==1)
    		{
    			a=rd()^ans,b=rd()^ans;
    			ra=find(a),rb=find(b);
    			if(s[ra].siz>s[rb].siz)	swap(ra,rb);
    			insert(rt[now],rt[now+1],1,n,s[rb].fa,s[rb].siz+s[ra].siz,s[rb].fa),now++;
    			insert(rt[now],rt[now+1],1,n,s[ra].fa,s[ra].siz,s[rb].fa),now++;
    		}
    		if(c==2)
    		{
    			a=rd()^ans;
    			rt[++now]=rt[to[a]];
    		}
    		if(c==3)
    		{
    			a=rd()^ans,b=rd()^ans;
    			ra=find(a),rb=find(b);
    			printf("%d
    ",ans=(s[ra].fa==s[rb].fa));
    		}
    		to[i]=now;
    	}
    	return 0;
    }
  • 相关阅读:
    成为明星程序员的10个提示
    每天写出好代码的5个建议
    收集开发相关网站
    Class.getDeclaredFields()和Class.getFields()的区别。 Class.getMethods()和Class.getDeclaredMethods()的区别。
    Oracle数据库插入过程中特殊符号
    @JsonIgnore注解|@JsonProperty
    基本linux命令
    linux基本概述
    php.ini模块
    一个购物车类(session实现的且为单例模式)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6895073.html
Copyright © 2020-2023  润新知