BZOJ3674: 可持久化并查集加强版 rope

来源:互联网 发布:mac os 10.11.6 编辑:程序博客网 时间:2024/06/01 08:58

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 < n,m <= 2*10^5
只要将数组可持久化即可,但如果使用rope,需要注意以下几个方面:
1.不要一开始将所有rope实体化。只创建指针,需要复制时再用拷贝构造函数新建对象,这样既快又省空间。
2.路径压缩时,如果find的结果和当前值相等,就不要修改了,否则会MLE
3.如果不涉及更改就不用复制了,直接拷贝指针即可。

#include<cstdio>#include<algorithm>#include<ext/rope>#define gm 200001using namespace __gnu_cxx;using std::swap;typedef rope<int> rp;rp* ar[gm];int find(rp *r,int x){    int y=r->at(x);    if(x==y) return x;    int z=find(r,y);    if(y==z) return y;    r->replace(x,z);    return z;}inline void merge(rp *r,int a,int b){    a=find(r,a),b=find(r,b);    if(a!=b)    {        if(rand()&1) swap(a,b);        r->replace(a,b);    }}int last=0;inline int is_same(rp *r,int a,int b){    return last=find(r,a)==find(r,b);}int n,m,o,a,b;int base[gm];int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;++i) base[i]=i;    ar[0]=new rp(base,n+1);    for(int i=1;i<=m;++i)    {        scanf("%d",&o);        if(o==1)        {            ar[i]=new rp(*ar[i-1]);            scanf("%d%d",&a,&b);            merge(ar[i],a^last,b^last);        }        else if(o==2)        {            scanf("%d",&a);            ar[i]=new rp(*ar[a^last]);        }        else        {            scanf("%d%d",&a,&b);            printf("%d\n",is_same(ar[i-1],a^last,b^last));            ar[i]=new rp(*ar[i-1]);        }    }    return 0;}
0 0