P3402 【模板】可持久化并查集 (可持久化数组+并查集)

https://www.luogu.org/problemnew/show/P3402

题意很简单。

这道题,看见题目就知道应该是可持久化数据结构。而且题目还说了上一个版本的的情况。所以肯定就是主席树有关。

既然是可持久化并查集,那么就应该等于 可持久化数组+并查集。

我最开始弄了一个什么压缩的路径的可持久化数组+并查集,结果错得不知所措,只能过样例。。。现在还是不知道怎么错了。

结果就到处乱想,还差点想到了LCT上去.到现在都不知道能不能用路径压缩的并查集写。

然后看了有人用不带路径的并查集过了,然后就想了想,是挺好写的,看着是挺浪费内存的,但不过管他的。写了几发,错了几发

然后T了一发,情况就是并查集退化为一条链,很费时间,最后看见大佬用的均摊树的深度。然后写了一下,发现确实是这样的。

具体步骤如下:

在主席树上,查询某一个版本中一个点的父亲,然后跳到它的父亲,重复上面的步骤直到找到root。

关于深度的均摊,这方面吧深度小的往深度大上面并,同时深度小的并上后深度加1,这样是可以过的。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
const int M=20;
typedef long long ll;
typedef unsigned long long ull;
int root[N],lson[N*20],rson[N*20];
int tot=0,n,m,fa[N*20],deep[N*20];
int build(int l,int r)
{
    int now=++tot;
    if(l==r){
        fa[now]=l;
        return now;
    }
    int mid=(l+r)>>1;
    lson[now]=build(l,mid);
    rson[now]=build(mid+1,r);
    return now;
}
int update(int last,int l,int r,int pos,int ff)
{
    int now=++tot;
    rson[now]=rson[last],fa[now]=fa[last];
    lson[now]=lson[last],deep[now]=deep[last];
    if(l==r){
        fa[now]=ff;
        return now;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) lson[now]=update(lson[last],l,mid,pos,ff);
    else rson[now]=update(rson[last],mid+1,r,pos,ff);
    return now;
}
int query(int ed,int l,int r,int pos)
{
    if(l==r) return ed;
    int mid=(l+r)>>1;
    if(pos<=mid) return query(lson[ed],l,mid,pos);
    else return query(rson[ed],mid+1,r,pos);
}
void add(int rt,int l,int r,int pos)
{
    if(l==r){
        deep[rt]++;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) add(lson[rt],l,mid,pos);
    else add(rson[rt],mid+1,r,pos);
}

int ffind(int ed,int x)
{
    int fx=query(ed,1,n,x);
    if(x==fa[fx]) return fx;
    return ffind(ed,fa[fx]);
}

int main()
{
    int op,x,y;
    scanf("%d%d",&n,&m);
    root[0]=build(1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&op);
        if(op==1){
            root[i]=root[i-1];
            scanf("%d%d",&x,&y);
            int fx=ffind(root[i-1],x);
            int fy=ffind(root[i-1],y);
            if(fa[fx]==fa[fy]) continue;
            if(deep[fx]>deep[fy]) swap(fx,fy);
            root[i]=update(root[i-1],1,n,fa[fx],fa[fy]);
            add(root[i],1,n,fa[fy]);
        }
        if(op==2){
            scanf("%d",&x);
            root[i]=root[x];
        }
        if(op==3){
            root[i]=root[i-1];
            scanf("%d%d",&x,&y);
            int fx=ffind(root[i-1],x);
            int fy=ffind(root[i-1],y);
            if(fa[fx]==fa[fy]) puts("1");
            else puts("0");
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值