[BZOJ3674]可持久化并查集 可持久化线段树维护数组

本文介绍了一种结合并查集与可持久化线段树的数据结构实现方法,通过具体代码示例展示了如何用C++实现这一结构,并应用于解决实际问题。文章涉及了节点构建、插入操作及查询等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于并查集数组fa[i],可以拿可持久化线段树来维护

好像要按秩合并才能过吧

/**************************************************************
    Problem: 3674
    User: di4CoveRy
    Language: C++
    Result: Accepted
    Time:1748 ms
    Memory:98196 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
 
#define mid ((l+r)>>1)
 
#define N 200050 
 
using namespace std;
 
int x,v,n,m;
struct hyy_tree{
    int tr[20*N],num[N],h[N],ls[20*N],rs[20*N],cnt,rt;
    int build(int l,int r,int &t) {
        if (!t) t = ++cnt;
        if (l == r) return tr[t] = num[l];
        build(l,mid,ls[t]); build(mid+1,r,rs[t]);
    }
    void ins(int l,int r,int las,int &t) {
        if (!t) t = ++cnt;
        if (l == r) { tr[t] = v; return ; }
        if (x <= mid) 
            ins(l,mid,ls[las],ls[t]) , rs[t] = rs[las];
        else
            ins(mid+1,r,rs[las],rs[t]),ls[t] = ls[las];
    }
    int query(int l,int r,int t) {
        if (l == r) return tr[t];
        if (x <= mid) 
            return query(l,mid,ls[t]);
        else
            return query(mid+1,r,rs[t]);
    }
    int ask(int w,int his) {
        x = w; return query(1,n,his);
    }   
}fa,siz;
 
int get(int u) {
    int cur = fa.ask(u,fa.rt); 
    if (cur == u) return cur; else return get(cur);
}
 
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) fa.num[i] = i , siz.num[i] = 1;
     
     fa.build(1,n, fa.h[0]);
    siz.build(1,n,siz.h[0]);
     
     fa.rt =  fa.h[0];
    siz.rt = siz.h[0];
    int ans = 0;
    for (int _=1;_<=m;_++) {
        int cmd=0; scanf("%d",&cmd);
        if (cmd == 1) {
            int a,b; scanf("%d%d",&a,&b); 
            a ^= ans; b ^= ans;
            int p = get(a) , q = get(b);
            int pp = siz.ask(p,siz.rt) , qq = siz.ask(q,siz.rt);
            if (p == q) continue;
            if (pp < qq) swap(p,q);
            x = q , v = p; 
             fa.ins(1,n, fa.rt, fa.h[_]);
             fa.rt =  fa.h[_];
             
            x = p , v = pp+qq; 
            siz.ins(1,n,siz.rt,siz.h[_]);
            siz.rt = siz.h[_];
        }
        if (cmd == 2) {
            int k=0; scanf("%d",&k);
            k ^= ans;
             fa.h[_] =  fa.rt =  fa.h[k];
            siz.h[_] = siz.rt = siz.h[k];
        }
        if (cmd == 3) {
            int a=0,b=0; scanf("%d%d",&a,&b);
            a ^= ans , b ^= ans;
            int p = get(a) , q = get(b);
            ans = p == q;
            printf("%d\n",ans);
             fa.h[_] =  fa.rt;
            siz.h[_] = siz.rt;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值