• 专题训练之并查集(带权并查集、可持久化并查集)


    推荐一个博客:https://blog.csdn.net/tribleave/article/details/72878239 并查集和带权并查集

    带权并查集:在并查集的基础上,对其中的每一个元素赋有某些值。在对并查集进行路径压缩和合并操作时,这些权值具有一定属性,即可将他们与父节点的关系,变化为与所在树的根结点关系。

    带权并查集习题:

    1.(POJ1182)http://poj.org/problem?id=1182

    推荐几个讲解详细的博客:https://blog.csdn.net/niushuai666/article/details/6981689 从向量的角度看问题

    分析:难点在于:A.路径压缩时的关系域的更新

    B.条件判断时,若两个点的根节点不同则合并;若根节点相同则按照当前给定关系与原本的关系进行判断。

    总的来说就是两点之间的偏移量大小的确定

    注意:改组只有一组,多组读入会WA

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=5e4+10;
     6 struct node{
     7     int pre;
     8     int realtion;
     9 }f[maxn];
    10 
    11 int find(int x)
    12 {
    13     if ( !f[x].pre ) return x;
    14     int tmp=f[x].pre;
    15     f[x].pre=find(tmp);
    16     f[x].realtion=(f[x].realtion+f[tmp].realtion)%3;
    17     return f[x].pre;
    18 }
    19 
    20 int main()
    21 {
    22     int n,k,op,a,b,rt1,rt2,ans;
    23     scanf("%d%d",&n,&k);
    24     ans=0;
    25     memset(f,0,sizeof(f));
    26     for ( int i=1;i<=k;i++ )
    27     {
    28         scanf("%d%d%d",&op,&a,&b);
    29         if ( a>n || b>n )
    30         {
    31             ans++;
    32             continue;
    33         }
    34         if ( op==2 && a==b )
    35         {
    36             ans++;
    37             continue;
    38         }
    39         rt1=find(a);
    40         rt2=find(b);
    41         if ( rt1!=rt2 )
    42         {
    43             f[rt2].pre=rt1;
    44             f[rt2].realtion=(f[a].realtion+op-1+3-f[b].realtion)%3;
    45         }
    46         else
    47         {
    48             if ( op==1 && f[a].realtion!=f[b].realtion )
    49             {
    50                 ans++;
    51                 continue;
    52             }
    53             if ( op==2 && ((3-f[a].realtion+f[b].realtion)%3!=1) )
    54             {
    55                 ans++;
    56                 continue;
    57             }
    58         }
    59     }
    60     printf("%d
    ",ans);
    61     return 0;
    62 }
    POJ1182

    2.(POJ1988)http://poj.org/problem?id=1988

    题意:初始时有N堆砖块,每堆有一个(编号为1-N)。现在有q个操作,

    操作分2种:M X Y 将含编号X的那堆放置在编号为Y堆的上方

    C X 含编号为X的砖块下方有多少个砖块

    分析:设置数组d[i]表示编号为d的下方有多少块砖(同时也能表示编号为i的点到其所在树的树根的距离),d[i]初始化为0。还需要设置数组num[i]表示当i为一堆最下面的那个砖块(所在树的数根)总共包含多少个点。对于两种操作:查找时i到数根的距离等于i到原来数根的距离+原来数根到新树根的记录。合并时,原来的数根到新数根的距离为新树根包含点的个数,新树根点的个数加上原来数根点的个数。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=3e4+10;
     6 int f[maxn],d[maxn],num[maxn];
     7 
     8 
     9 int find(int x)
    10 {
    11     if ( f[x]==-1 ) return x;
    12     int tmp=find(f[x]);
    13     if ( tmp==f[x] ) return f[x];
    14     else
    15     {
    16         d[x]+=d[f[x]];
    17         return f[x]=tmp;    
    18     }
    19 }
    20 
    21 int main()
    22 {
    23     int n,i,j,x,y,q;
    24     char s[10];
    25     while ( scanf("%d",&q)!=EOF )
    26     {
    27         for ( i=1;i<=30000;i++ )
    28         {
    29             f[i]=-1;
    30             d[i]=0;
    31             num[i]=1;
    32         }
    33         while ( q-- )
    34         {
    35             scanf("%s",s);
    36             if ( s[0]=='M' )
    37             {
    38                 scanf("%d%d",&x,&y);
    39                 int fx=find(x);
    40                 int fy=find(y);
    41                 if ( fx!=fy ) 
    42                 {
    43                     f[fx]=fy;
    44                     d[fx]=num[fy];
    45                     num[fy]+=num[fx];
    46                 }
    47             }
    48             else
    49             {
    50                 scanf("%d",&x);
    51                 int fx=find(x);
    52                 printf("%d
    ",d[x]);
    53             }
    54         }
    55     }
    56     return 0;
    57 }
    POJ1988

    3.(HDOJ3047)http://acm.hdu.edu.cn/showproblem.php?pid=3047

    题意:有n个人坐在zjnu体育馆里面,然后给出m个他们之间的距离, A B X, 代表B的座位比A多X. 然后求出这m个关系之间有多少个错误,所谓错误就是当前这个关系与之前的有冲突。

    分析:大致用POJ1182,每个点的relation为其于其父节点的距离(也可以说是父节点到其的偏移量),为正代表父节点的座位号比该节点大,为负代表父节点的座位号比该节点小。每次更新时注意偏移量的变化(特别注意正负),每次访问若为同一个点则判断A到B的偏移量是否为x即可

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=5e4+10;
     6 struct node{
     7     int pre;
     8     int relation;
     9 }f[maxn];
    10 
    11 int find(int x)
    12 {
    13     if ( f[x].pre==-1 ) return x;
    14     int tmp=f[x].pre;
    15     f[x].pre=find(tmp);
    16     f[x].relation=(f[x].relation+f[tmp].relation);
    17     return f[x].pre;
    18 }
    19 
    20 
    21 int main()
    22 {
    23     int n,m,i,j,k,x,y,d,fx,fy,num,ans;
    24     while ( scanf("%d%d",&n,&m)!=EOF )
    25     {
    26         for ( i=1;i<=n;i++ )
    27         {
    28             f[i].pre=-1;
    29             f[i].relation=0;
    30         }
    31         ans=0;
    32         while ( m-- )
    33         {
    34             scanf("%d%d%d",&x,&y,&d);
    35             fx=find(x);
    36             fy=find(y);
    37             if ( fx==fy )
    38             {
    39                 if ( -f[x].relation+d+f[y].relation!=0 )
    40                 {
    41                     ans++;
    42                     continue;
    43                 }
    44             }
    45             else
    46             {
    47                 f[fx].pre=fy;
    48                 f[fx].relation=-f[x].relation+d+f[y].relation;
    49             }
    50         }
    51         printf("%d
    ",ans);
    52     }    
    53     return 0;
    54 }
    HDOJ3047
  • 相关阅读:
    Web service是什么?
    SQL截取字符串
    SQL Server中使用索引性能的比较
    一个C#中webservice的初级例子(一)
    short s1 = 1; s1 = s1 + 1;有错而short s1 = 1; s1 += 1正确。为何?
    SQL索引
    ORDER BY 子句在子查询和公用表表达式中无效的一种解决办法使用表变量
    创建 索引,
    时间的重叠
    SQLServer Datetime数据类型的转换
  • 原文地址:https://www.cnblogs.com/HDUjackyan/p/9313333.html
Copyright © 2020-2023  润新知