bzoj 3674: 可持久化并查集加强版

bzoj 3674: 可持久化并查集加强版

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

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

知识点:可持久化并查集

这是一道模板题。
可持久化并查集还蛮好玩的。
就是相当于用主席树搞一个可持久化数组,维护f和h值。f是在并查集里面的父亲,h是启发式合并的秩。
虽然说理论上启发式合并+路径压缩会快,可是只开启发式合并好像实测更快。
算了不管了,就这样吧。

代码

这个是路径压缩+启发式合并的可持久化并查集。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
const int N = 220000, T = 1e7 + 10;
int read() {
    char ch = getchar();int x = 0, f = 1;
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f; 
}
int n, m, sz;
int rt[N], ls[T], rs[T], f[T], h[T];

void Build(int &p, int L, int R) {
    p = ++sz;
    if(L == R) {f[p] = L; return;}
    int mid = L + R >> 1;
    Build(ls[p], L, mid);
    Build(rs[p], mid + 1, R);
}
void Modify(int lp, int &cp, int L, int R, int pos, int val) {
    cp = ++sz;
    if(L == R) {f[cp] = val; h[cp] = h[lp]; return ;} 
    int mid = L + R >> 1;
    if(pos <= mid) rs[cp] = rs[lp], Modify(ls[lp], ls[cp], L, mid, pos, val);
    else ls[cp] = ls[lp], Modify(rs[lp], rs[cp], mid + 1, R, pos, val);
}
void Add(int p, int L, int R, int pos) {
    if(L == R) {++h[p]; return;}
    int mid = L + R >> 1;
    if(pos <= mid) Add(ls[p], L, mid, pos);
    else Add(rs[p], mid + 1, R, pos);
}
int Query(int p, int L, int R, int pos) {
    if(L == R) return p;
    int mid = L + R >> 1;
    if(pos <= mid) return Query(ls[p], L, mid, pos);
    else return Query(rs[p], mid + 1, R, pos);
} 
int F(int k, int x) {
    int p = Query(k, 1, n, x);
    if(x == f[p]) return p;
    int t = F(k, f[p]);
    Modify(k, k, 1, n, f[p], t);
    return t;
}
void Merge(int i, int u, int v) {
    int p = F(rt[i], u), q = F(rt[i], v);
    if(f[p] == f[q]) return;
    if(h[p] < h[q]) swap(p, q);
    Modify(rt[i - 1], rt[i], 1, n, f[q], f[p]);
    if(h[p] == h[q]) Add(rt[i], 1, n, f[p]);
}
int main() {
    n = read(); m = read();
    Build(rt[0], 1, n);
    for(int i = 1;i <= m; ++i) {
        int opt = read();
        if(opt == 2) {rt[i] = rt[read()];}
        else {
            int x = read(), y = read();
            rt[i] = rt[i - 1];
            if(opt == 1) Merge(i, x, y);
            else printf("%d\n", f[F(rt[i], x)] == f[F(rt[i], y)] ? 1 : 0);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值