• bzoj 3673: 可持久化并查集 by zky


    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 1229  Solved: 561
    [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

    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
     
    题解:
      用可持久化线段树维护并查集的信息,每棵线段树的叶子节点的fa值就是在当前线段树的时间下这个叶子节点表示的集合所在的根集合。查找操作就是不断地找叶子节点,如果这个叶子节点维护的fa值不是自己,就回到根节点找他fa的fa。
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<vector>
     8 #include<queue>
     9 using namespace std;
    10 const int maxn=3*1e4;
    11 int N,M;
    12 struct Tree{
    13     int lc,rc,fa;
    14 }tr[40*maxn];
    15 int root[maxn],siz;
    16 inline void build(int &i,int l,int r){
    17     i=++siz;
    18     if(l==r){
    19         tr[i].fa=l; return ;
    20     }
    21     int mid=(l+r)>>1;
    22     if(l<=mid) build(tr[i].lc,l,mid);
    23     if(mid+1<=r) build(tr[i].rc,mid+1,r);
    24 }
    25 inline void change(int last,int &i,int l,int r,int pos,int now){
    26     i=++siz;
    27     tr[i].lc=tr[last].lc; tr[i].rc=tr[last].rc;
    28     if(l==r){
    29         tr[i].fa=now; return ;
    30     }
    31     int mid=(l+r)>>1;
    32     if(pos<=mid) change(tr[last].lc,tr[i].lc,l,mid,pos,now);
    33     else change(tr[last].rc,tr[i].rc,mid+1,r,pos,now);
    34 }
    35 inline int query(int i,int l,int r,int pos){//返回叶节点为 pos的节点编号 
    36     if(l==r) return i;
    37     int mid=(l+r)>>1;
    38     if(pos<=mid) query(tr[i].lc,l,mid,pos);
    39     else query(tr[i].rc,mid+1,r,pos);
    40 }
    41 inline int find(int i,int pos){//找到pos所在集合的根节点 
    42     int x=query(i,1,N,pos);
    43     if(tr[x].fa==pos) return x;
    44     return find(i,tr[x].fa); 
    45 }
    46 int main(){
    47     scanf("%d%d",&N,&M);
    48     build(root[0],1,N);//初始化 
    49     for(int i=1,kin,a,b;i<=M;i++){
    50         scanf("%d",&kin);
    51         if(kin==1){//合并 a b
    52             root[i]=root[i-1];
    53             scanf("%d%d",&a,&b);
    54             int p=find(root[i],a),q=find(root[i],b);
    55             if(tr[p].fa!=tr[q].fa){
    56                 change(root[i-1],root[i],1,N,tr[p].fa,tr[q].fa);
    57             }
    58         }
    59         else if(kin==2){//回到第a次操作前 
    60             scanf("%d",&a);
    61             root[i]=root[a];
    62         }
    63         else if(kin==3){//判断是否在同一集合 
    64             root[i]=root[i-1];
    65             scanf("%d%d",&a,&b);
    66             int p=find(root[i],a),q=find(root[i],b);
    67             if(tr[p].fa==tr[q].fa) puts("1");
    68             else puts("0");
    69         }
    70     }
    71     return 0;
    72 }
  • 相关阅读:
    单例实现c++
    c++智能指针实现方式1
    c++中处理输入输出的方法
    makefile函数
    5. Longest Palindromic Substring
    go 语言中常用的包
    ubuntu14.04 boost动态库找不到 libboost_system.so.1.58.0
    boost-asio-cpp-network-programming阅读笔记
    链接-装载-库,读书笔记
    leecode第二百一十七题(存在重复元素)
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/5239368.html
Copyright © 2020-2023  润新知