• 【Acwing并查集】238. 银河英雄传说


    238. 银河英雄传说 - AcWing题库

    题意:

    思路:

    并查集维护两个信息:每个连通块的size和每个结点之间的距离

    对于连通块的size,只需要在合并的时候维护一下就好了

    对于每个结点之间的距离,我们考虑类似于树上差分的思想,先处理每个结点离根节点的距离,再差分减一下就好了

    那么问题就转化成维护每个结点离根节点的距离

    由于维护的信息的主体是结点,那么就不能只在合并的时候维护了,在find的时候也需要维护

    我们将连通块v接到连通块u下面时,更新连通块v的每个结点离根节点的距离,因为根节点换了,同时也要更新连通块的size

    更新连通块v每个结点的信息是通过find回溯的时候更新的,我们给u的原先的根节点+=size(u)就行,这样在之后如果访问连通块v的某个结点时,find在回溯时会把这个结点和连通块v原先根节点之间的所有结点都更新,同时也将这些结点路径压缩,这有点像线段树懒标记的感觉

    路径压缩后,虽然原先的链式结构被破坏,但是距离信息保留在d数组中,因此查询的时候直接查询d[x]就好了,d数组相当于是前缀和数组

    如果之后又要合并已经被路径压缩的结点,也是同样的道理,先更新连通块根节点(相当于打个标记),然后在查询的时候回溯下传求前缀和就好了

    Code:

    1. #include
    2. using namespace std;
    3. const int mxn=3e4+10;
    4. string op;
    5. int n,x,y;
    6. int f[mxn],sz[mxn],d[mxn];
    7. int find(int x){
    8. if(f[x]!=x){
    9. int rt=find(f[x]);
    10. d[x]+=d[f[x]];
    11. f[x]=rt;
    12. }
    13. return f[x];
    14. }
    15. void join(int u,int v){
    16. int f1=find(u),f2=find(v);
    17. if(f1!=f2){
    18. f[f1]=f2;
    19. d[f1]=sz[f2];
    20. sz[f2]+=sz[f1];
    21. }
    22. }
    23. int main(){
    24. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    25. cin>>n;
    26. for(int i=1;i1;
    27. for(int i=1;i<=n;i++){
    28. cin>>op>>x>>y;
    29. if(op=="M"){
    30. join(x,y);
    31. }else{
    32. int a=find(x),b=find(y);
    33. if(a!=b) cout<<-1<<'\n';
    34. else cout<<max(0,abs(d[x]-d[y])-1)<<'\n';
    35. }
    36. }
    37. }

    总结:

    当要我们维护联通块信息、涉及到分类、判环、维护传递性关系时都可以用并查集

    在写并查集之前先考虑好并查集维护的对象

    并查集维护两种信息:连通块信息和结点信息

    维护连通块信息时,只需在合并的时候维护就好了,维护完连通块之后可以考虑缩点

    维护结点信息时,要在find和merge时一起维护,在merge的时候给根节点打标记,在find的时候回溯下传标记

  • 相关阅读:
    计算机组成原理——基础入门总结(二)
    MyBatis 源码分析之 Mapper 接口代理对象生成及方法执行
    基于微信小程序的校园活动平台的设计与实现
    协议定制 + Json序列化反序列化
    Leetcode 907. 子数组的最小值之和
    稀土/铜催化剂电催化CO2制C2+或CH4
    云计算实验(HCL模拟器)
    小黑子的SSM整合
    idea2021.2.3安装炫酷插件activate-power-mode失败解决方案
    使用 Nginx 和 SSL 访问 Python Flask 应用的教程
  • 原文地址:https://blog.csdn.net/weixin_62528401/article/details/127820025