BZOJ 3673: 可持久化并查集(可持久化并查集+启发式合并)

http://www.lydsy.com/JudgeOnline/problem.php?id=3673

题意:

 

思路:

可持久化数组可以用可持久化线段树来实现,并查集的查询操作和原来的一般并查集操作是差不多的,只不过是在线段树上操作。需要注意的是并查集的合并,需要按秩来进行启发式合并。

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2*10000+5;

int n,m,tot;
int t[maxn*50],h[maxn*50];

struct node
{
    int l,r,fa;
}a[maxn*50];

int build(int l, int r)
{
    int root = ++tot;
    if(l==r)  {a[root].fa = l;return root;}
    int mid = (l+r)>>1;
    a[root].l = build(l,mid);
    a[root].r = build(mid+1,r);
    return root;
}

int query(int root, int x, int l, int r)
{
    if(l==r)  return root;
    int mid = (l+r)>>1;
    if(x<=mid)  return query(a[root].l,x,l,mid);
    else return query(a[root].r,x,mid+1,r);
}

int finds(int root, int x)
{
    int p = query(root,x,1,n);
    if(x == a[p].fa)  return p;
    else return finds(root,a[p].fa);
}

int modify(int pre, int x, int y, int l, int r)
{
    int root = ++tot;
    if(l==r)
    {
        a[root].fa = y;
        h[root] = h[pre]; //这个不能忘
        return root;
    }
    a[root].l = a[pre].l, a[root].r = a[pre].r;
    int mid = (l+r)>>1;
    if(x<=mid)  a[root].l = modify(a[pre].l, x, y, l, mid);
    else a[root].r = modify(a[pre].r, x, y, mid+1, r);
    return root;
}

void update(int root, int x, int l, int r)
{
    if(l==r)  {h[root]++;return;}
    int mid = (l+r)>>1;
    if(x<=mid)  update(a[root].l,x, l, mid);
    else update(a[root].r,x, mid+1, r);
}

void unions(int x, int y, int i)
{
    if(h[x]>h[y]) swap(x,y);
    t[i] = modify(t[i-1],a[x].fa,a[y].fa,1,n);  //因为上面的交换,所以这里用fa
    if(h[x]==h[y])  update(t[i],a[y].fa,1,n);  //如果深度相等,则插入后深度会+1
}

int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    tot = 0;
    t[0] = build(1,n);
    for(int i=1;i<=m;i++)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int aa,bb;
            scanf("%d%d",&aa,&bb);
            t[i] = t[i-1];
            int x = finds(t[i],aa);
            int y = finds(t[i],bb);
            if(a[x].fa != a[y].fa)  unions(x,y,i);
        }
        if(op==2)
        {
            int aa;
            scanf("%d",&aa);
            t[i] = t[aa];
        }
        if(op==3)
        {
            int aa,bb;
            scanf("%d%d",&aa,&bb);
            t[i] = t[i-1];
            int x = finds(t[i],aa);
            int y = finds(t[i],bb);
            if(a[x].fa == a[y].fa)  puts("1");
            else puts("0");
        }
    }
    return 0;
}

  

posted @ 2017-11-24 08:50  Kayden_Cheung  阅读(234)  评论(0编辑  收藏  举报
//目录