• 2020牛客多校第三场 G


    Operating on a Graph

    题意:

    给定一个无向图,有n个点,点i初始时属于集合i。给出q个操作,每次操作针对集合oi,将与集合oi相邻的集合全部加入集合oi中(若集合oi已经不存在了就无事发生)。在q个操作结束之后,问每个点属于的集合。

    解法:

    显然应该用并查集维护每个点属于哪个集合。问题在于进行操作时,如何确定和集合oi相邻的集合?因此每个集合必须要有一个容器存储其中的点,这个容器还要能够快速合并。因此选用List作为集合的容器。

    在一次操作中,有一些点被展开,和它相邻的点属于的集合都被归入oi,可以发现,这个点只需要被扩展一次就够了,因为之后它相邻的点一定是和它属于同一个集合的。

    所以在一次操作中,只需要将list中原有的所有点都扩展并弹出,并加入相邻集合的点,同时维护并查集关系。

    时间复杂度为O(nlogn+m)大概

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=8e5+5;
    vector<int>E[maxn];
    list<int>ls[maxn];
    int fa[maxn];
    int find(int x){
        return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    int unite(int u,int v){
        int fu=find(u);
        int fv=find(v);
        if(fu!=fv){
            fa[fu]=fv;
            ls[fv].splice(ls[fv].end(),ls[fu]);
        }
    }
    void bfs(int oi){
        if(find(oi)!=oi){//不存在该集合
            return;
        }
        int size=ls[oi].size();//只要展开集合中原有的点,防止展开新的点
        for(int i=0;i<size;i++){
            int curnode=ls[oi].front();
            for(auto v:E[curnode]){
                unite(v,oi);//将v加入oi
            }
            ls[oi].pop_front();
        }
    }
    void init(int n){
        for(int i=0;i<n;i++){
            fa[i]=i;
            E[i].clear();
            ls[i].clear();
            ls[i].push_back(i);//初始化集合元素为自己
        }
    }
    int main () {
        int T;
        scanf("%d",&T);
        while(T--){
            int n,m;
            scanf("%d%d",&n,&m);
            init(n+3);
            for(int i=1;i<=m;i++){
                int u,v;
                scanf("%d%d",&u,&v);
                E[u].push_back(v);
                E[v].push_back(u);
            }
            int q;
            scanf("%d",&q);
            while(q--){
                int oi;
                scanf("%d",&oi);
                bfs(oi);
            }
            for(int i=0;i<n;i++){
                printf("%d",find(i));
                if(i<n){
                    printf(" ");
                }
            }
            puts("");
        }
    }
    
  • 相关阅读:
    Integer.highestOneBit(int i)方法的作用与底层实现
    一文搞明白位运算、补码、反码、原码
    Zookeeper如何解决脑裂问题
    Zookeeper请求处理原理分析
    Linux 设备驱动之 UIO 机制
    virtio guest side implementation: PCI, virtio device, virtio net and virtqueue
    DPDK之(八)——vhost库
    Red Hat OpenStack 10的新特性
    探秘DPDK Virtio的不同路径
    2017版:KVM 性能优化之内存优化
  • 原文地址:https://www.cnblogs.com/ucprer/p/13343411.html
Copyright © 2020-2023  润新知