zoukankan      html  css  js  c++  java
  • 并查集

    1.模板题

    洛谷3367

    我们把这个问题换一种方式表述

    1 u v 表示v是u的祖先

    2 u v 问你u和v是不是同一家族

    此处设一些变量

    anc[i]表示i的祖先,一开始anc[i]=0。

    然后对于输入的信息1 u v

    我们找到u和v所已知最早的祖先fu,fv;

    while(!anc[u]) u=anc[u];

    类似于此

    此时如果fu==fv说明之前已经有信息把u,v连接在了一起,则不做处理;

    如果fu!=fv,那么另anc[fu]=fv;

    (注意此题我们可能无法确定fu与fv谁是最早祖先,但是不影响正确性)

    对于输入的询问2 u v

    我们也是找到 fu   fv

    看fu fv 是否相等就可以了

    然而我们仔细思考这个过程发现在极端情况下,耗时会十分的长

    例如给定信息表示1与2,2与3,3与4,4与5........n与n-1的关系

    那么这些元素将会连成一条链

    我们每次查询1 的最早祖先, 都要找n次

    这样就会使时间复杂度过高

    思考我们怎么优化这个过程呢?

    路径压缩:

    首先对于一个家族里面所有的人,我不关心别的,只关心这个家族最早的祖先

    那么我们是不是可以考虑把每个点都直接连接在哪个最早祖先上。

    下面给出代码:

     1 #include<cstdio>
     2 const int N=10005;
     3 int anc[N];
     4 int fi(int a){
     5     int b=a;
     6     while(anc[b]) b=anc[b];
     7     while(anc[a]){
     8         int t=anc[a];
     9         anc[a]=b;
    10         a=t;
    11     }
    12     return b;
    13 }
    14 int main(){
    15     int n,m;
    16     scanf("%d%d",&n,&m);
    17     while(m--){
    18         int id,u,v;
    19         scanf("%d%d%d",&id,&u,&v);
    20         int fu=fi(u),fv=fi(v);
    21         if(id==2){
    22             if(fu==fv) printf("Y
    ");
    23             else printf("N
    ");
    24         }
    25         else if(fu!=fv) anc[fu]=fv;
    26     }
    27     return 0;
    28 } 

    一些加权并查集的题解:

    luogu2024

    bzoj1202

  • 相关阅读:
    《计算机网络 自顶向下方法》 第3章 运输层 Part1
    Java 字符串截取问题
    Java 字符排序问题
    Linux 下实时查看日志
    Java项目 打war包方法
    Linux 下 安装jdk 1.7
    Linux 下安装jetty服务器
    Linux 系统下安装 rz/sz 命令及使用说明
    Xshell
    Linux 常用命令大全
  • 原文地址:https://www.cnblogs.com/bzmd/p/10572859.html
Copyright © 2011-2022 走看看