BZOJ 3674 可持久化并查集加强版(主席树变形)

3673: 可持久化并查集 by zky

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 2515  Solved: 1107
[Submit][Status][Discuss]

Description

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

0<n,m<=2*10^4

Input

Output

Sample Input

5 6
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2

Sample Output

1
0
1

HINT

Source

出题人大SB

题目链接:BZOJ 3674

原来并查集也是可以可持久化的,其思想应该是在于用可持久化数据结构来维护一个前缀记录,由于普通的并查集一开始每一个节点的祖先都是本身,因此要多一个建树的操作,把所有的叶子节点的祖先都处理好,然后这题是并查集,并不需要差分的思想,也就是说更新或者查询只需要用到一个root点,其他的做法跟普通的并查集差不多,详细的可以看黄大牛的博客:http://hzwer.com/3997.html

代码:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 2e5 + 7;
struct seg
{
    int lson, rson;
    int pre;
};
seg T[N * 40];
int root[N], tot;
int n;

void init()
{
    CLR(root, 0);
    tot = 0;
}
void build(int &cur, int l, int r)
{
    cur = ++tot;
    T[cur].lson = T[cur].rson = 0;
    if (l == r)
        T[cur].pre = l;
    else
    {
        int mid = MID(l, r);
        build(T[cur].lson, l, mid);
        build(T[cur].rson, mid + 1, r);
    }
}
void update(int &cur, int ori, int l, int r, int pos, int pre)
{
    cur = ++tot;
    T[cur] = T[ori];
    if (l == r)
    {
        T[cur].pre = pre;
        return ;
    }
    else
    {
        int mid = MID(l, r);
        if (pos <= mid)
            update(T[cur].lson, T[ori].lson, l, mid, pos, pre);
        else
            update(T[cur].rson, T[ori].rson, mid + 1, r, pos, pre);
    }
}
int query(int k, int l, int r, int pos) //返回子节点位置
{
    if (l == r)
        return k;
    else
    {
        int mid = MID(l, r);
        if (pos <= mid)
            return query(T[k].lson, l, mid, pos);
        else
            return query(T[k].rson, mid + 1, r, pos);
    }
}
int Find(int k, int pre)
{
    int idx = query(k, 1, n, pre);
    if (pre == T[idx].pre)
        return pre;
    else
        return Find(k, T[idx].pre);
}
int main(void)
{
    int m, i, a, b, k, ops;
    while (~scanf("%d%d", &n, &m))
    {
        init();
        int ans = 0;
        build(root[0], 1, n);
        for (i = 1; i <= m; ++i)
        {
            scanf("%d", &ops);
            if (ops == 1)
            {
                scanf("%d%d", &a, &b);
                a ^= ans;
                b ^= ans;
                root[i] = root[i - 1];
                int fa = Find(root[i], a);
                int fb = Find(root[i], b);
                if (fa != fb)
                    update(root[i], root[i - 1], 1, n, fb, fa);
            }
            else if (ops == 2)
            {
                scanf("%d", &k);
                k ^= ans;
                root[i] = root[k];
            }
            else if (ops == 3)
            {
                scanf("%d%d", &a, &b);
                a ^= ans;
                b ^= ans;
                root[i] = root[i - 1];
                int fa = Find(root[i], a);
                int fb = Find(root[i], b);
                printf("%d\n", ans = (fa == fb));
            }
        }
    }
    return 0;
}
时间: 2024-10-12 22:51:23

BZOJ 3674 可持久化并查集加强版(主席树变形)的相关文章

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

3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 2605  Solved: 977[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:…… n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状

BZOJ 3674 可持久化并查集加强版 可持久化并查集

题目大意:同3673 强制在线 同3673 仅仅只是慢了一些0.0 这道题仅仅写路径压缩比仅仅写启示式合并要快一点点 两个都写就慢的要死0.0 改代码RE的可能是内存不够 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 200200 using namespace std; struct Tree{ Tree *ls,*rs; int nu

【BZOJ】3673: 可持久化并查集 by zky &amp; 3674: 可持久化并查集加强版(可持久化线段树)

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 http://www.lydsy.com/JudgeOnline/problem.php?id=3673 双倍经验啦啦啦.. 给主席树换了个名称果然高大上... 首先要可持久化并查集其实就是可持久化数组... 那么因为数组的形式是这样的$P[x]$,那么我们用一种数据结构实现查找x返回对应的$P[x]$即可啦啦啦. 然后那么我所学的可持久化目前只有主席树QAQ哪天去写写fhqtreap...

BZOJ 3673 可持久化并查集 by zky &amp;&amp; 3674 可持久化并查集加强版

题目大意:维护一种数据结构实现可持久化并查集. 思路:利用可持久化线段树实现可持久化数组维护可持久化并查集.(不知道3674哪里加强了... CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define RANGE 8000010 #define MAX 200200 using namespace std; struct SegTree

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

Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 3592  Solved: 1337[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:…… n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询

可持久化并查集加强版 BZOJ 3674

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 3225  Solved: 1192[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后--hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可

bzoj3673可持久化并查集 by zky&amp;&amp;bzoj3674可持久化并查集加强版

bzoj3673可持久化并查集 by zky 题意: 维护可以恢复到第k次操作后的并查集. 题解: 用可持久化线段树维护并查集的fa数组和秩(在并查集里的深度),不能路径压缩所以用按秩启发式合并,可以使合并均摊复杂度为O(nlog2n).可持久化线段树实际上就是在更新节点时按主席树的插入方式新建一条路径(其实主席树就是可持久化权值线段树). 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

bzoj3674 可持久化并查集加强版

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的初始值为00<n,m<=2*10^5 Samp

【BZOJ3674】可持久化并查集加强版

可持久化并查集我觉得就是可持久化数组的一种应用.可持久化数组,顾名思义,就是有历史版本的数组,那么如果我们暴力修改储存的话,修改O(n)查询O(1),空间O(n*m),这样肯定不可行,那么我们发现主席树有这样的功能,他可以快速复制,修改O(log),查询O(log),空间(m*log),是一个可行的方案.然后我们可持久化f数组维护fa,每次按照深度启发式合并,不进行路径压缩,这样能保证时间复杂度位单次O(log^2),空间复杂度为O(2*n+m*log).我不知道为什么不路径压缩,路径压缩是完全