zoukankan      html  css  js  c++  java
  • BZOJ3673 : 可持久化并查集

    题目没有强制在线!

    考虑离线做法。

    把操作建立成一棵树的结构,然后按照欧拉序遍历,每次转移要么是一次合并操作,要么是一次撤销合并操作,可以看成是分离操作。

    用LCT维护集合,合并就是加边,分离就是删边。

    时间复杂度$O(mlog n)$

     

    #include<cstdio>
    #define N 20010
    int n,m,i,op,x,y,id[N],ans[N],last,g[N],nxt[N],v[N],q[N],w[N],ed,G[N],NXT[N],V[N],Q[N],W[N],ED,f[N],son[N][2],tmp[N];bool rev[N];
    inline void swap(int&x,int&y){int z=x;x=y;y=z;}
    inline bool isroot(int x){return !f[x]||(son[f[x]][0]!=x&&son[f[x]][1]!=x);}
    inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
    inline void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;
        if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];f[y]=x;son[x][w^1]=y;
    }
    inline void splay(int x){
      int s=1,i=x,y;tmp[1]=i;
      while(!isroot(i))tmp[++s]=i=f[i];
      while(s)pb(tmp[s--]);
      while(!isroot(x)){
        y=f[x];
        if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
    }
    inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y;}
    inline int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
    inline void makeroot(int x){access(x);splay(x);rev1(x);}
    inline void link(int x,int y){makeroot(x);f[x]=y;access(x);}
    inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;}
    inline void cut(int x,int y){makeroot(x);cutf(y);}
    inline void add(int x,int y,int a,int b){v[++ed]=y;q[ed]=a;w[ed]=b;nxt[ed]=g[x];g[x]=ed;}
    inline void ADD(int x,int y,int a,int b){V[++ED]=y;Q[ED]=a;W[ED]=b;NXT[ED]=G[x];G[x]=ED;}
    void dfs(int x){
      int i;
      for(i=G[x];i;i=NXT[i])ans[V[i]]=root(Q[i])==root(W[i]);
      for(i=g[x];i;i=nxt[i])if(root(q[i])!=root(w[i]))link(q[i],w[i]),dfs(v[i]),cut(q[i],w[i]);else dfs(v[i]);
    }
    int main(){
      for(scanf("%d%d",&n,&m),i=1;i<=m;ans[i++]=-1){
        scanf("%d",&op);
        if(op==1)scanf("%d%d",&x,&y),add(last,id[i]=i,x,y),last=i;
        if(op==2)scanf("%d",&x),last=id[i]=id[x];
        if(op==3)scanf("%d%d",&x,&y),ADD(last,i,x,y),id[i]=last;
      }
      for(dfs(0),i=1;i<=m;i++)if(~ans[i])printf("%d
    ",ans[i]);
      return 0;
    }
    

      

  • 相关阅读:
    Linux内存运维操作及常用命令
    Quartz定时任务
    Spark DataSource Option 参数
    Hadoop HDFS命令
    Java,Scala:JDBCUtil,MySqlUtil,PhoenixJDBC
    RedisUtil,Redis工具类
    通过脚本本地下载Jar包
    Redis五种数据类型-设置key的过期时间
    spark整合Phoenix相关案例
    Spark Dataset DataFrame空值null,NaN判断和处理
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403225.html
Copyright © 2011-2022 走看看