zoukankan      html  css  js  c++  java
  • b_lq_网络分析(两个点不在同一连通块就新开一个根 | 带权并查集优化)

    在某个节点发送一条信息,信息会发送到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接或间接相邻的节点都收到了信息。
    所有发送和接收的节点都会将信息存储下来。一条信息只存储一次。
    给出小明连接和测试的过程,请计算出每个节点存储信息的大小。

    这题要跟着输入数据一步一步模拟才不容易出错,就是你不能连完边再跑逻辑;
    这是最暴力的方法(超时)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int n,m,fa[N],ans[N];
    vector<int> g[N];
    int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);}
    int main() {
        scanf("%d%d", &n,&m);
        for (int i=1; i<N; i++) fa[i]=i;
        while (m--) {
            int t,u,v; scanf("%d%d%d", &t,&u,&v);
            if (t==1) {
                fa[find(u)]=find(v);
            } else {
                int fu=find(u);
                for (int i=1; i<=n; i++) if (find(i)==fu)
                    ans[i]+=v;
            }
        }
        for (int i=1; i<=n; i++) printf("%d ",ans[i]);
        return 0;
    }
    

    优化思路
    先让一个附加的公共根统率一堆连通块的结点,初始情况下发送数据包时只让这个公共根存储,最后树形遍历的时候,就让公共根发送自己存储的数据包给子节点存储

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int n,m,fa[N],d[N];
    vector<int> g[N];
    int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);}
    void dfs(int u, int fa) {
        d[u]+=d[fa];
        for (int v : g[u]) if (fa!=v)
            dfs(v,u);
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin>>n>>m;
        int root=n+1;
        for (int i=1; i<N; i++) fa[i]=i;
        for (int i=0; i<m; i++) {
            int op,u,v; cin>>op>>u>>v;
            if (op==1) {
                int fu=find(u), fv=find(v);
                if (fu!=fv) {
                    fa[fu]=fa[fv]=root;
                    g[root].push_back(fu);
                    g[root++].push_back(fv); //每次只要两个点不在一个连通块上,就新开一个连通块;这样既可保证未连接的点收不到"别人"发的数据,又可保证后面的点合并之后,数据的可接受性,且只接受后面合并后发送的数据
                }
            } else {
                d[find(u)]+=v;
            }
        }
        for (int i=n+1; i<root; i++) if (fa[i]==i) dfs(i,0);  //如果i是根,则将i的数据扩散到i的子节点
        for (int i=1; i<=n; i++) printf("%d ", d[i]);
        return 0;
    }
    

    更优的做法是:用带权并查集(用的还不是很熟),复杂度是 mlogn

  • 相关阅读:
    黑客书架上的书籍(转)
    vc 得到文件后缀名(转)
    配置IIS7(转)
    vs2008 目标框架 发布遇到的问题(转)
    CListCtrl用法(转)
    T400 折腾
    VS2008和.NET Framework3.5新功能(转)
    sql 2008 ctp 安装
    关于定位lsass内存中的明文密码(转)
    NT系统下木马进程的隐藏与检测(转)
  • 原文地址:https://www.cnblogs.com/wdt1/p/13779661.html
Copyright © 2011-2022 走看看