Description

自从 zkysb 出了可持久化并查集后......

hzwer: 乱写能 AC, 暴力踩标程

KuribohG: 我不路径压缩就过了!

ndsf: 暴力就可以轻松虐!

zky:. ......

\(n\) 个集合,\(m\) 个操作, 格式如下:

  1. 1 a b 合并 \(a, b\) 所在集合
  2. 2 k 回到第 \(k\) 次操作之后的状态 (查询算作操作)
  3. 3 a b 询问 \(a, b\) 是否属于同一集合, 是则输出 \(1\), 否则输出 \(0\).

请注意本题采用强制在线, 所给的 \(a, b, k\) 均经过加密, 加密方法为 \(x = x\ \text{xor}\ lastans\),\(lastans\) 的初始值为 \(0\)

Input

第一行两个整数,\(n, m\);

接下来的 \(m\) 行如题目中所述.

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

Data Range

对于所有数据, 满足:\(0 \leq n, m \leq 2 \times 10^5\)

Explanation

这道题写完把代码改两行直接就可以交到 bzoj3673 上了~

由于这道题是一道很裸的裸题, 所以就没有什么可说的了.

为了这个写了两个可持久化的 template, 然后套了上去. 改了几个 flag 然后交过了~ 但是其实一开始是 MLE 了几次的 (人生第一次 MLE), 后来不得已才又改了几发模板.

所以说用模板写东西虽然很 OOP (雾), 但是效率毕竟低. 我没试过 inline 大法, 但是 可能那也没什么用.

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <map>
#include <stdexcept>
#include <cstring>

using namespace std;

// #define RA_DO_HANDLE_EXCEPTION 1
// #define RA_MALLOC_ON_DEMAND 1
// #define RA_UNLIMITED_TIMESTAMPS 1

template <typename _Type>
class retroactive_array
{
private:
    // Constants, only used if required
    static const int _node_pool_size = 10000100;
    static const int _timestamp_size = 200100;
    // Segment tree structural implementation
    class ra_node {
    public:
        _Type value;
        ra_node *lc, *rc;
    };
    int _size;
    #ifdef RA_UNLIMITED_TIMESTAMPS
    std::map<int, ra_node*> root;
    #else
    ra_node* root[_timestamp_size];
    #endif
    // Node allocation units
    #ifdef RA_MALLOC_ON_DEMAND
    ra_node* alloc_node(void)
    {
        ra_node *p = new ra_node;
        return p;
    }
    #else
    ra_node _node_pool[_node_pool_size];
    int _node_pool_cntr;
    ra_node* alloc_node(void)
    {
        #ifdef RA_DO_HANDLE_EXCEPTION
        if (_node_pool_cntr >= _node_pool_size)
            throw std::out_of_range("Memory pool overflow");
        #endif
        ra_node *p = &_node_pool[_node_pool_cntr++];
        return p;
    }
    #endif
    // Recursive tree building unit
    typedef _Type gen_function(int);
    ra_node* build_tree(int l, int r, gen_function func)
    {
        ra_node *p = this->alloc_node();
        if (l == r) {
            p->value = func(l);
            return p;
        }
        int mid = (l + r) >> 1;
        p->lc = this->build_tree(l, mid, func);
        p->rc = this->build_tree(mid + 1, r, func);
        return p;
    }
    // Querying data from structure
    _Type query(ra_node *p, int l, int r, int pos)
    {
        if (l == r)
            return p->value;
        int mid = (l + r) >> 1;
        if (pos <= mid)
            return this->query(p->lc, l, mid, pos);
        else
            return this->query(p->rc, mid + 1, r, pos);
    }
    // Modifying data in structure
    ra_node* modify(ra_node *p, int l, int r, int pos, _Type val)
    {
        // Creating clone of this node
        ra_node *q = this->alloc_node();
        q->value = p->value;
        q->lc = p->lc;
        q->rc = p->rc;
        // Working on segment tree
        if (l == r) {
            q->value = val;
            return q;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid)
            q->lc = this->modify(q->lc, l, mid, pos, val);
        else
            q->rc = this->modify(q->rc, mid + 1, r, pos, val);
        return q;
    }
private:
    // Maintaining functions for invoking upper-level retroactive array
    // functions on I/O
    size_t get_size(void)
    {
        return this->_size;
    }
    bool has_time(int time)
    {
        if (this->root[time] == NULL)
            return false;
        return true;
    }
    void create_fork(int time, int time_old = 0)
    {
        if (time == time_old)
            return ;
        #ifdef RA_DO_HANDLE_EXCEPTION
        if (this->root[time_old] == NULL)
            throw std::out_of_range("Unexpected time of fork source supplied.");
        #endif
        if (this->root[time] != NULL)
            return ;
        ra_node *o_root = this->root[time_old];
        ra_node *c_root = this->alloc_node();
        // Copy data for duplication
        c_root->value = o_root->value;
        c_root->lc = o_root->lc;
        c_root->rc = o_root->rc;
        // Putting back into map
        this->root[time] = c_root;
        return ;
    }
    _Type get_data(int time, int pos)
    {
        #ifdef RA_DO_HANDLE_EXCEPTION
        if (pos < 0 || pos > this->_size)
            throw std::out_of_range("Indexing limits out of bound.");
        #endif
        // Retrieving root at position
        ra_node *c_root = this->root[time];
        #ifdef RA_DO_HANDLE_EXCEPTION
        if (c_root == NULL)
            throw std::out_of_range("Unexpected time supplied.");
        #endif
        // Getting data
        _Type res = this->query(c_root, 1, _size, pos);
        return res;
    }
    void set_data(int time, int pos, _Type val)
    {
        #ifdef RA_DO_HANDLE_EXCEPTION
        if (pos < 0 || pos > this->_size)
            throw std::out_of_range("Indexing limits out of bound.");
        #endif
        // Retrieving root at position
        ra_node *c_root = this->root[time];
        #ifdef RA_DO_HANDLE_EXCEPTION
        if (c_root == NULL)
            throw std::out_of_range("Please create a fork before setting data.");
        #endif
        // Modifying data
        c_root = this->modify(c_root, 1, _size, pos, val);
        this->root[time] = c_root;
        return ;
    }
    void init_array(int n, gen_function func)
    {
        this->_size = n;
        ra_node *c_root = this->build_tree(1, _size, func);
        #ifdef RA_UNLIMITED_TIMESTAMPS
        this->root.clear();
        #else
        memset(root, 0, sizeof(root));
        #endif
        this->root[0] = c_root;
        return ;
    }
    _Type _default_zero;
    _Type _zero_override_func(int in) {
        return _default_zero; }
    void init_array(int n, _Type zero)
    {
        this->_default_zero = zero;
        this->init_array(n, _zero_override_func);
        return ;
    }
// protected:
public:
    // Data wrapper for positions (third-level)
    class ra_val_wrapper {
    protected:
        retroactive_array* _ra;
        int _time, _pos;
    public:
        ra_val_wrapper(retroactive_array* _ra, int _time, int _pos) {
            this->_ra = _ra;
            this->_time = _time;
            this->_pos = _pos;
            return ; }
        ra_val_wrapper& operator = (ra_val_wrapper in) {
            *this = _Type(in);
            return *this; }
        ra_val_wrapper& operator = (_Type in) {
            this->_ra->set_data(this->_time, this->_pos, in);
            return *this; }
        operator _Type (void) {
            _Type val = this->_ra->get_data(this->_time, this->_pos);
            return val; }
    };
    // Data wrapper for time (second-level)
    class ra_time_wrapper {
    protected:
        retroactive_array* _ra;
        int _time;
    public:
        ra_time_wrapper(retroactive_array* _ra, int _time) {
            this->_ra = _ra;
            this->_time = _time;
            return ; }
        ra_val_wrapper operator [] (int pos) {
            ra_val_wrapper rvw(this->_ra, this->_time, pos);
            return rvw; }
    };
    // Wrapping time
    ra_time_wrapper call_time_wrapper(int time)
    {
        // Checking if fork required
        this->create_fork(time);
        // Returning wrapper
        ra_time_wrapper rtw(this, time);
        return rtw;
    }
public:
    retroactive_array(void) {
        this->_size = 0;
        #ifndef RA_MALLOC_ON_DEMAND
        memset(_node_pool, 0, sizeof(_node_pool));
        _node_pool_cntr = 0;
        #endif
        return ; }
    retroactive_array(int n, _Type zero) {
        this->init_array(n, zero);
        return ; }
    void init(int n, gen_function func) {
        this->init_array(n, func);
        return ; }
    void init(int n, _Type zero) {
        this->init_array(n, zero);
        return ; }
    size_t size(void) {
        return this->get_size(); }
    _Type get(int time, int pos) {
        return this->get_data(time, pos); }
    void set(int time, int pos, _Type val) {
        this->set_data(time, pos, val);
        return ; }
    void fork(int time, int time_old = 0) {
        this->create_fork(time, time_old);
        return ; }
    ra_time_wrapper operator [] (int time) {
        return this->call_time_wrapper(time); }
};

struct rds_unit {
    int par, size;
    rds_unit(void) { par = size = 0; }
    rds_unit(int _1, int _2) { par = _1, size = _2; }
};
rds_unit ra_generator(int pos) {
    rds_unit ru(pos, 1);
    return ru;
}

class retroactive_disjoint_set
{
private:
    int n;
    retroactive_array<rds_unit> ra;
public:
    void fork(int time, int time_old = 0) {
        ra.fork(time, time_old);
        return ; }
    int find(int time, int p)
    {
        rds_unit q_ru = ra.get(time, p);
        int q = q_ru.par;
        if (p == q)
            return p;
        return find(time, q);
    }
    bool joined(int time, int p, int q)
    {
        p = find(time, p);
        q = find(time, q);
        if (p == q)
            return true;
        return false;
    }
    void join(int time, int p, int q)
    {
        p = find(time, p);
        q = find(time, q);
        if (p == q)
            return ;
        rds_unit p_ru = ra.get(time, p),
                 q_ru = ra.get(time, q);
        // Ensure rank balance
        if (p_ru.size > q_ru.size)
            std::swap(p, q),
            std::swap(p_ru, q_ru);
        // Joining
        q_ru.size += p_ru.size;
        p_ru.par = q;
        ra.set(time, p, p_ru);
        ra.set(time, q, q_ru);
        return ;
    }
    void init(int n)
    {
        this->n = n;
        ra.init(n, ra_generator);
        return ;
    }
};

retroactive_disjoint_set rds;

int n, m;

int main(int argc, char** argv)
{
    scanf("%d%d", &n, &m);
    rds.init(n);
    int last = 0;
    for (int i = 1; i <= m; i++) {
        int func, a, b;
        scanf("%d", &func);
        if (func == 1) {
            scanf("%d%d", &a, &b);
            a = a ^ last;
            b = b ^ last;
            rds.fork(i, i - 1);
            rds.join(i, a, b);
        } else if (func == 2) {
            scanf("%d", &a);
            a = a ^ last;
            rds.fork(i, a);
        } else if (func == 3) {
            scanf("%d%d", &a, &b);
            a = a ^ last;
            b = b ^ last;
            rds.fork(i, i - 1);
            last = rds.joined(i, a, b);
            printf("%d\n", last);
        }
    }
    return 0;
}