2020牛客暑期多校第三场G-Operating on a Graph(并查集+list)

题目大意:给你n个点,m条边,现在有q次操作,每次一个x,表示将与x所连的所有点归并到x团里面,问最后每个点属于哪个团。

输入

5
4 3
0 1
1 2
2 3
4
0 1 3 0
4 3
0 1
1 2
2 3
2
0 2
4 3
0 1
1 2
2 3
2
0 3
4 1
1 3
1
2
5 5
0 1
0 2
1 2
1 3
3 4
3
4 4 0

输出

0 0 0 0
2 2 2 2
0 0 3 3
0 1 2 3
0 0 0 0 0

看见团和合并之类的,很容易联想到并查集,每次合并的时候我们将每个点的祖宗设置为x就好了(注意,如果x的祖宗不是自己的话就说明它已经被合并了,这个x团中就是空的,我们直接跳过)。接下来就是将两个祖宗团的所有点合并了,我们需要用一个数据结构来实现这种操作,而list应该是一个比较理想的容器,它的splice方法是比较高效的

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e6+10;

struct Edge
{
    int to,next;
}eg[mac<<1];
int head[mac],father[mac],num=0;
list<int>group[mac];
bool vis[mac];

void add(int u,int v)
{
    eg[++num]=Edge{v,head[u]};
    head[u]=num;
}

int find(int x){return x==father[x]?x:father[x]=find(father[x]);}

void unions(int u,int v)
{
    int fu=find(u),fv=find(v);
    if (fu!=fv){
        father[fu]=fv;
        group[fv].splice(group[fv].end(),group[fu]);
    }
}

int main(int argc, char const *argv[])
{
    int t,n,m;
    scanf ("%d",&t);
    while (t--){
        scanf ("%d%d",&n,&m);
        num=0;
        for (int i=0; i<n+10; i++){
            head[i]=-1;father[i]=i;
            vis[i]=0; group[i].clear();
            group[i].push_back(i);
        }
        for (int i=1; i<=m; i++){
            int u,v;
            scanf ("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        int q;
        scanf ("%d",&q);
        while (q--){
            int x;
            scanf ("%d",&x);
            int gkd=find(x);
            if (gkd!=x) continue;
            int len=group[x].size();
            for (int i=0; i<len; i++){//!!注意这里不能用size。
                int u=group[x].front();
                for (int j=head[u]; j!=-1; j=eg[j].next){
                    int v=eg[j].to;
                    unions(v,x);
                    if (vis[v]) continue;
                    group[x].push_back(v);
                    vis[v]=1;
                }
                group[x].pop_front();
            }
        }
        for (int i=0; i<n; i++)
            printf("%d ",find(i));
        printf("\n");
    }
    return 0;
}

 

上一篇:【SSLOJ】最短路


下一篇:通过SqlClr制作Sql自动化批量执行脚本