2020牛客暑期多校训练营(第三场)G.Operating on a Graph

2020牛客暑期多校训练营(第三场)G.Operating on a Graph

题目链接

题目描述

You are given a graph containing n vertices and m edges. Vertices are numbered from 0 to n-1. Initially, vertex i belongs to group i. We define a group A is connected to group B if and only if there exists at least an edge that connects the two vertices which belong to A and B respectively.

Now we will do q operations on this graph. The i-th operation is represented by an integer o i o_i oi.

In i-th operation, if there are no vertices belong to group o i o_i oi, nothing happens. Otherwise, for all vertices belong to a group which is connected to o i o_i oi, those vertices will belong to group o i o_i oi after this operation.

Now you are also given the q operations. Please answer each vertex belongs to which group after all operations.

输入描述:

The first line contains one integer t ( 1 ≤ t ≤ 1.6 × 1 0 5 ) t (1 \le t \le 1.6 \times 10^5) t(1t1.6×105) — the number of test cases.

The first line of each test contains two positive integers n and m ( 2 ≤ n ≤ 8 × 1 0 5 , 1 ≤ m ≤ 8 × 1 0 5 ) (2 \le n \le 8 \times 10^5 , 1 \le m \le 8 \times 10^5) (2n8×105,1m8×105) — the number of vertices and edges in the given graph.

The following are m lines. Each of them contains two integers x and y, indicating there is an edge between vertex x and vertex y ( 0 ≤ x < y < n 0 \le x < y < n 0x<y<n, there are no duplicate edges in the same test)

The following line contains one integer q ( 1 ≤ q ≤ 8 × 1 0 5 ) (1 \le q \le 8 \times 10^5) (1q8×105) – the number of operations in this test. Then there is one more line contains q integers o 1 , o 2 , … , o q ( 0 ≤ o i < n ) o_1, o_2, \ldots, o_q (0 \le o_i < n) o1,o2,,oq(0oi<n).

The sum of n across the test cases doesn’t exceed 8 × 1 0 5 8 \times 10^5 8×105.

The sum of m across the test cases doesn’t exceed 8 × 1 0 5 8 \times 10^5 8×105.

And the sum of q across the test cases doesn’t exceed 8 × 1 0 5 8 \times 10^5 8×105.

输出描述:

For each test, output one line contains n integers — the i-th integer of them representing the group that the vertex i-1 belongs to.

示例1

输入

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

这题很明显的并查集,但是比较难看出是并查集+链表,我用别的数据结构就 T 了,我也是第一次学到了链表的拼接函数,还是见得太少~
我们用链表存储某一个块 o i o_i oi 的所有结点,每次遍历表头,存入所有和表头相连的未被访问的点,同时将点所属的块与表头的块用 s p l i c e splice splice 函数拼接,每次遍历整个链表一遍,最后输出时找每个顶点的父亲结点即可,AC代码如下:

#include
using namespace std;
typedef long long ll;
const int N=8e5+5;
int t,n,m,u,v,q,k,father[N],vis[N];
vector<int>G[N];
list<int>L[N];
int Findfather(int x){
    return father[x]==x?x:father[x]=Findfather(father[x]);
}

void Union(int x,int y){
    x=Findfather(x),y=Findfather(y);
    if(x!=y) father[y]=x,L[x].splice(L[x].end(),L[y]);
}

void init(){
    for(int i=0;i<=n;i++)
        father[i]=i,vis[i]=0,G[i].clear(),L[i].clear(),L[i].push_back(i);
}

void bfs(int u){
    if(Findfather(u)!=u) return;
    int len=L[u].size();
    for(int i=0;i<len;i++){
        auto j=L[u].front();
        for(auto v:G[j]){
            Union(u,v);
            if(vis[v]) continue;
            L[u].push_back(v);
            vis[v]=1;
        }
        L[u].pop_front();
    }
}

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        init();
        while(m--){
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        scanf("%d",&q);
        while(q--){
            scanf("%d",&k);
            bfs(k);
        }
        for(int i=0;i<n;i++){
            printf("%d ",Findfather(i));
        }
        printf("\n");
    }
}

你可能感兴趣的:(并查集,list,牛客)