• 备战蓝桥杯之并查集刷题之删除


    题目比较模板,但是也扩展了许多以前不知道的知识点,记录一下比较有启发性的题。

    目录

    1.并查集之删除操作---创点转移:

    2.并查集之删除操作---逆向思考:


    1.并查集之删除操作---创点转移:

    1和3都是并查集的基础操作,这里就不说了(以前讲过),我们主要看2,我们把2的操作拆分成先去除p,再合并p,那么我们如何删除呢?

    我们可以真的去删,但是我们需要修改子节点的连接,会增加时间复杂度并且比较麻烦。

    于是我们采用用空间换时间的策略,我们可以再创建一个点,当我们删3时,我们可以保留原来的位置,但是我们需要为3提供真实的点,于是我们用类似映射的方法real[3]=新创建的点,这样子,我们就把3的“空壳”留在原地方,而把3的“灵魂”存在了其他地方,这样其他的点也就不用操作了。

    下面是AC代码:

    1. #include
    2. using namespace std;
    3. int n,m,p,q,c,fa[200010],real1[100005],cc;
    4. struct node{
    5. int cnt;
    6. long long sum;
    7. }root[200010];
    8. int find(int x){
    9. if(fa[x]==x) return x;
    10. return fa[x]=find(fa[x]);
    11. }
    12. void merge(int x,int y){
    13. root[find(y)].cnt+=root[find(x)].cnt;
    14. root[find(y)].sum+=root[find(x)].sum;
    15. fa[find(x)]=find(y);
    16. }
    17. void del(int x){
    18. root[find(real1[x])].cnt--;
    19. root[find(real1[x])].sum-=x;
    20. real1[x]=++cc;
    21. root[cc].cnt=1;
    22. root[cc].sum=x;
    23. fa[cc]=cc;
    24. }
    25. signed main(){
    26. while(cin>>n>>m){
    27. for(int i=1;i<=n;i++){
    28. fa[i]=i;
    29. real1[i]=i;
    30. root[i].cnt=1;
    31. root[i].sum=i;
    32. }
    33. cc=n;
    34. for(int i=1;i<=m;i++){
    35. cin>>c;
    36. if(c==1){
    37. cin>>p>>q;
    38. if(find(real1[p])==find(real1[q])) continue;
    39. merge(real1[p],real1[q]);
    40. }
    41. else if(c==2){
    42. cin>>p>>q;
    43. if(find(real1[p])==find(real1[q])) continue;
    44. del(p);
    45. merge(real1[p],real1[q]);
    46. }
    47. else{
    48. cin>>p;
    49. node ss=root[find(real1[p])];
    50. cout<" "<
    51. }
    52. }}
    53. }

    这里有几点需要注意:

    1.多组输入注意对会新创建的值的改变,这里的cc每次都应从n开始。

    2.注意合并时的判断条件必不可少,因为这里的并查集带了权值,重复时会导致值的重复相加。

    2.并查集之删除操作---逆向思考:

    以前有讲过,这里找到了个题目算是填坑了。我们先记录删的,把删的全删了,这样从反方向就是创建了。

    下面是AC代码:

    1. #include
    2. using namespace std;
    3. int n,m,x,y,k,fa[400010],huei[400010],head[400010],cnt,ck[400010];
    4. int hh[400010];
    5. struct node{
    6. int dian,next;
    7. }edge[400010];
    8. void merge(int x,int y){
    9. edge[++cnt].dian=y;
    10. edge[cnt].next=head[x];
    11. head[x]=cnt;
    12. }
    13. int find(int x){
    14. if(fa[x]==x) return x;
    15. return fa[x]=find(fa[x]);
    16. }
    17. void merge1(int x,int y){
    18. fa[find(x)]=find(y);
    19. }
    20. int main(){
    21. cin>>n>>m;
    22. memset(head,-1,sizeof(head));
    23. for(int i=1;i<=m;i++){
    24. scanf("%d%d",&x,&y);
    25. merge(x,y);
    26. merge(y,x);
    27. }
    28. cin>>k;
    29. for(int i=1;i<=k;i++){
    30. scanf("%d",&huei[i]);
    31. ck[huei[i]]=1;
    32. }
    33. for(int i=0;i<=n-1;i++) fa[i]=i;
    34. for(int i=0;i<=n-1;i++){
    35. if(ck[i]==1) continue;
    36. if(head[i]==-1) continue;
    37. for(int j=head[i];j!=-1;j=edge[j].next){
    38. if(ck[edge[j].dian]==1) continue;
    39. if(find(edge[j].dian)==find(i)) continue;
    40. merge1(edge[j].dian,i);
    41. }
    42. }
    43. int cc=0;
    44. for(int i=0;i<=n-1;i++){
    45. if(fa[i]==i&&ck[i]==0) cc++;
    46. }
    47. hh[k+1]=cc;
    48. for(int i=k;i>=1;i--){
    49. int gg=huei[i];
    50. ck[gg]=0;
    51. cc++;
    52. for(int j=head[gg];j!=-1;j=edge[j].next){
    53. if(ck[edge[j].dian]==1) continue;
    54. if(find(edge[j].dian)!=find(gg)) cc--;
    55. merge1(edge[j].dian,gg);
    56. }
    57. hh[i]=cc;
    58. }
    59. for(int i=1;i<=k+1;i++){
    60. printf("%d\n",hh[i]);
    61. }
    62. }

  • 相关阅读:
    pdfh5在线预览pdf文件
    【Android性能】【流畅度】概念初识
    nginx负载均衡和高可用
    我现在是如何听歌的?
    线程中的LockSapport于线程中断(一)
    【深入理解C++】new/delete和new[]/delete[]探秘
    业务流程可视化-让你的流程图"Run"起来(7.运行状态持久化&轻量工作流支持)
    【m98】RtpSequenceNumberMap:记录RTP序列号与时间戳
    java计算机毕业设计企业公开招聘系统源码+数据库+lw文档+系统
    计算机系统的层次结构
  • 原文地址:https://blog.csdn.net/cocoack/article/details/136273032