BZOJ 3673 可持久化并查集 by zky && BZOJ 3674 可持久化并查集加强版 可持久化线段树...

既然有了可持久化数组,就有可持久化并查集。。

由于上课讲过说是只能按秩合并(但是我也不确定。。。),所以就先写了按秩合并,相当于是维护fa[]和rk[]

getf就是在这棵树中找,直到找到一个点的fa[x]==x

之所以这种写法不能路径压缩,个人理解是因为路径压缩会破坏原先的结构。。。反正我魔改改错了。。。先咕着路径压缩qwq

下面是加强版的代码。。。只有按秩合并

#include<cstdio>
#include<iostream>
#define R register int
#define pc(x) putchar(x)
using namespace std;
const int N=2E5+10,M=1E7+10;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,m,tot,lst,crt;
int rt[N],ls[M],rs[M],vl[M],rk[M];
inline void build(int& tr,int l,int r) { tr=++tot;
    if(l==r) {vl[tr]=l,rk[tr]=1; return; } R md=l+r>>1;
    build(ls[tr],l,md),build(rs[tr],md+1,r);
}
inline void ins(int& tr,int lst,int l,int r,int pos,int v) {
    tr=++tot,ls[tr]=ls[lst],rs[tr]=rs[lst],vl[tr]=vl[lst],rk[tr]=rk[lst]; 
    if(l==r) {vl[tr]=v; return ;} R md=l+r>>1; 
    pos<=md?ins(ls[tr],ls[lst],l,md,pos,v):ins(rs[tr],rs[lst],md+1,r,pos,v);
}
inline int getf(int tr,int l,int r,int pos) {
    if(l==r) {return pos==vl[tr]?tr:getf(rt[crt],1,n,vl[tr]);} R md=l+r>>1;
    return (pos<=md)?getf(ls[tr],l,md,pos):getf(rs[tr],md+1,r,pos);
}
inline void add(int& tr,int lst,int l,int r,int pos) {
    tr=++tot; ls[tr]=ls[lst],rs[tr]=rs[lst],vl[tr]=vl[lst],rk[tr]=rk[lst];
    if(l==r) {++rk[tr]; return ;} R md=l+r>>1;
    pos<=md?add(ls[tr],ls[lst],l,md,pos):add(rs[tr],rs[lst],md+1,r,pos);
}
signed main() {
    n=g(),m=g(); build(rt[0],1,n);
    for(R i=1;i<=m;++i) {
        R k=g(),a=g()^lst,b; if(k==1) { rt[i]=rt[i-1],crt=i;
            b=g()^lst; a=getf(rt[i],1,n,a); b=getf(rt[i],1,n,b);
            if(vl[a]!=vl[b]) {
                if(rk[a]<rk[b]) swap(a,b);
                ins(rt[i],rt[i-1],1,n,vl[b],vl[a]);
                if(rk[a]==rk[b]) add(rt[i],rt[i],1,n,vl[a]);
            } 
        } else if(k==2) rt[i]=rt[a];
        else { rt[i]=rt[i-1],crt=i; b=g()^lst;
            a=getf(rt[i],1,n,a),b=getf(rt[i],1,n,b);
            vl[a]==vl[b]?(lst=1,pc('1'),pc('\n')):(lst=0,pc('0'),pc('\n')); //cout<<"fasdhfjlkasdf"<<endl;
        }
    } //while(1);
}

2019.05.06

转载于:https://www.cnblogs.com/Jackpei/p/10819714.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值