bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集

题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673

   bzoj3674:https://www.lydsy.com/JudgeOnline/problem.php?id=3674

   洛谷P3402:https://www.luogu.org/problemnew/show/P3402

可持久化并查集!就是用主席树模拟并查集,真美!

路径压缩版:和并查集的相似之处想想感觉好妙;

但复杂度似乎有点不科学,bzoj 的两道题都能过,但洛谷上的模板过不了;

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=2e4+5,maxm=3e6+5;
//int const maxn=2e5+5,maxm=1e7+5;
int n,m,f[maxm],ls[maxm],rs[maxm],rt[maxn],cnt,ans;
void build(int &x,int l,int r)
{
    x=++cnt;
    if(l==r){f[x]=l; return;}
    int mid=((l+r)>>1);
    build(ls[x],l,mid); build(rs[x],mid+1,r);
}
void insert(int x,int &y,int l,int r,int pos,int val)
{
    y=++cnt;
    if(l==r){f[y]=val; return;}//不是f[pos] 
    int mid=((l+r)>>1);
    ls[y]=ls[x]; rs[y]=rs[x];
    if(pos<=mid)insert(ls[x],ls[y],l,mid,pos,val);
    else insert(rs[x],rs[y],mid+1,r,pos,val);
}
int query(int x,int l,int r,int pos)
{
    if(l==r)return f[x];
    int mid=((l+r)>>1);
    if(pos<=mid)return query(ls[x],l,mid,pos);
    else return query(rs[x],mid+1,r,pos);
}
int find(int &root,int pos)
{
    int tmp=query(root,1,n,pos);
    if(tmp==pos)return pos;
    int ret=find(root,tmp);
    insert(root,root,1,n,pos,ret);//路径压缩,修改root 
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);
    build(rt[0],1,n);
    for(int i=1,op,k,x,y;i<=m;i++)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x,&y);
//            x^=ans; y^=ans;
            int fx=find(rt[i-1],x),fy=find(rt[i-1],y);
            if(fx==fy)rt[i]=rt[i-1];
            else insert(rt[i-1],rt[i],1,n,fx,fy);
        }
        if(op==2)
        {
            scanf("%d",&k);
//            k^=ans;
            rt[i]=rt[k];
        }
        if(op==3)
        {
            scanf("%d%d",&x,&y);
//            x^=ans; y^=ans;
            int fx=find(rt[i-1],x),fy=find(rt[i-1],y);
            if(fx==fy)ans=1,printf("1\n");
            else ans=0,printf("0\n");
            rt[i]=rt[i-1];
        }
    }
    return 0;
}

按秩合并版:复杂度科学,写起来也很简洁,洛谷模板能过;

感觉数据结构写好了模板摆在那儿什么都能干,很方便啊。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=2e5+5,maxm=1e7+5;
int n,m,f[maxm],ls[maxm],rs[maxm],dep[maxm],rt[maxn],cnt,ans;
void build(int &x,int l,int r)
{
    x=++cnt;
    if(l==r){f[x]=l; dep[x]=1; return;}
    int mid=((l+r)>>1);
    build(ls[x],l,mid); build(rs[x],mid+1,r);
}
void insert(int x,int &y,int l,int r,int pos,int val)
{
    y=++cnt;
    if(l==r){f[y]=val; dep[y]=dep[x]; return;}
    int mid=((l+r)>>1);
    ls[y]=ls[x]; rs[y]=rs[x];
    if(pos<=mid)insert(ls[x],ls[y],l,mid,pos,val);
    else insert(rs[x],rs[y],mid+1,r,pos,val);
}
void add(int x,int &y,int l,int r,int val)
{
    y=++cnt;
    if(l==r){f[y]=val; dep[y]=dep[x]+1; return;} 
    int mid=((l+r)>>1);
    ls[y]=ls[x]; rs[y]=rs[x];
    if(val<=mid)add(ls[x],ls[y],l,mid,val);
    else add(rs[x],rs[y],mid+1,r,val);
}
int query(int x,int l,int r,int pos)
{
    if(l==r)return x;
    int mid=((l+r)>>1);
    if(pos<=mid)return query(ls[x],l,mid,pos);
    else return query(rs[x],mid+1,r,pos);
}
int find(int &root,int pos)
{
    int tmp=query(root,1,n,pos);
    if(f[tmp]==pos)return tmp;
    return find(root,f[tmp]);
}
int main()
{
    scanf("%d%d",&n,&m);
    build(rt[0],1,n);
    for(int i=1,op,k,x,y;i<=m;i++)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x,&y);
            int fx=find(rt[i-1],x),fy=find(rt[i-1],y);
            if(f[fx]==f[fy]){rt[i]=rt[i-1]; continue;}
            if(dep[fx]>dep[fy])swap(fx,fy);
            insert(rt[i-1],rt[i],1,n,f[fx],f[fy]);
            if(dep[fx]==dep[fy])add(rt[i],rt[i],1,n,f[fy]);//最大深度相等则合并后dep+1 
        }
        if(op==2)
        {
            scanf("%d",&k);
            rt[i]=rt[k];
        }
        if(op==3)
        {
            scanf("%d%d",&x,&y);
            int fx=find(rt[i-1],x),fy=find(rt[i-1],y);
            if(fx==fy)ans=1,printf("1\n");
            else ans=0,printf("0\n");
            rt[i]=rt[i-1];
        }
    }
    return 0;
}

 

posted @ 2018-07-19 20:58  Zinn  阅读(146)  评论(0编辑  收藏  举报