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

题意

给一张n个点m条边的无向图,一开始 i 号点属于第 i 个集合,每次对一个集合进行操作,将与该集合中的点相连的点所处的集合归到该集合中,有无效操作,Q次操作过后询问每个点所处集合。

看到这道题首先想到的就是并查集,但是无法快速能够向集合外连边的点。

我们可以发现这样一个性质,一个点作为集合边上的一点向外延伸最多进行一次,所以我们每次A集合向B集合合并的时候由B集合向A集合连边,下次对B集合操作的时候就遍历与它连通的集合,然后看这些集合所代表的点是否能向外连边,因为每个点只会向外扩展一次,所以便利之后就可以将邻接表重置。最后复杂度O( n log n )

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cstring>
 6 #define N 1000005
 7 using namespace std;
 8 int T,n,m;
 9 int zz1,zz2,zz3,a1[N],a2[N],a3[N];
10 struct ro{
11     int to,next;
12 }road1[N*2],road2[N*2];
13 void build1(int x,int y)
14 {
15     zz1++;
16     road1[zz1].to=y;
17     road1[zz1].next=a1[x];
18     a1[x]=zz1;
19 }
20 void build2(int x,int y)
21 {
22     zz2++;
23     road2[zz2].to=y;
24     road2[zz2].next=a2[x];
25     a2[x]=zz2;
26 }
27 bool fw[N];
28 int fa[N],Q,tmp[N],cnt;
29 int find(int x)
30 {
31     if(fa[x]==x)return x;
32     return fa[x]=find(fa[x]);
33 }
34 void dfs(int x)
35 {
36     for(int i=a2[x];i;i=road2[i].next)
37     {
38         int y=road2[i].to;
39         dfs(y);
40     }
41     for(int i=a1[x];i;i=road1[i].next)
42     {
43         int y=road1[i].to;
44         if(find(y)!=find(x)&&!fw[find(y)])
45         {
46             fw[find(y)]=1;
47             cnt++;
48             tmp[cnt]=find(y);
49         }
50     }
51 }
52 int main()
53 {
54     scanf("%d",&T);
55     while(T--)
56     {
57         scanf("%d%d",&n,&m);
58         zz1=0,zz2=0;
59         for(int i=1;i<=n;i++) fa[i]=i,a1[i]=a2[i]=0;
60         for(int i=1;i<=m;i++)
61         {
62             int x,y;
63             scanf("%d%d",&x,&y);
64             x++,y++;
65             build1(x,y);
66             build1(y,x);
67         }
68         scanf("%d",&Q);
69         cnt=0;
70         for(int i=1;i<=Q;i++)
71         {
72             int x;
73             scanf("%d",&x);x++;
74             if(find(x)!=x)continue;
75             dfs(x);
76             a2[x]=0;
77             for(int j=1;j<=cnt;j++)
78             {
79                 fw[tmp[j]]=0;
80                 build2(x,tmp[j]);
81                 fa[tmp[j]]=x;
82             }
83             cnt=0;
84         }
85         for(int i=1;i<=n;i++)
86         {
87             printf("%d ",find(i)-1);
88         }
89         printf("
");
90     }
91     return 0;
92 }
View Code
原文地址:https://www.cnblogs.com/liutianrui/p/13338802.html