题意:
给定n个点m条边的无向图,每个点一开始代表一种集合,共有n个集合
之后给出q次操作,每次询问将指定一个集合Oi,将所有与该集合有相连边的其他集合并入集合Oi
问经过q次操作后所有点属于哪个集合
做法:
之前没怎么遇见过启发式合并的题,所以赛时做法只是遍历所有点
每次从搜到的指定集合中的点开始dfs搜子树来合并。
这种做法会导致超时和在dfs找并查集子树时内存超限。
赛后了解到这就是启发式合并的基本思想,小集合并入大集合中
每次直接对集合进行操作,然后把小集合拼接在大集合上
基本上就是个启发式合并的板子题了
CODE
1 #include <bits/stdc++.h> 2 #define dbg(x) cout << #x << "=" << x << endl 3 #define eps 1e-8 4 #define pi acos(-1.0) 5 6 using namespace std; 7 typedef long long LL; 8 9 const int inf = 0x3f3f3f3f; 10 11 template<class T>inline void read(T &res) 12 { 13 char c;T flag=1; 14 while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; 15 while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; 16 } 17 18 namespace _buff { 19 const size_t BUFF = 1 << 19; 20 char ibuf[BUFF], *ib = ibuf, *ie = ibuf; 21 char getc() { 22 if (ib == ie) { 23 ib = ibuf; 24 ie = ibuf + fread(ibuf, 1, BUFF, stdin); 25 } 26 return ib == ie ? -1 : *ib++; 27 } 28 } 29 30 int qread() { 31 using namespace _buff; 32 int ret = 0; 33 bool pos = true; 34 char c = getc(); 35 for (; (c < '0' || c > '9') && c != '-'; c = getc()) { 36 assert(~c); 37 } 38 if (c == '-') { 39 pos = false; 40 c = getc(); 41 } 42 for (; c >= '0' && c <= '9'; c = getc()) { 43 ret = (ret << 3) + (ret << 1) + (c ^ 48); 44 } 45 return pos ? ret : -ret; 46 } 47 48 const int maxn = 8e5 + 7; 49 50 int t; 51 int n; 52 int fa[maxn]; 53 int m; 54 55 int fid(int x) { 56 return x == fa[x] ? x : fa[x] = fid(fa[x]); 57 } 58 59 // vector<int> g[maxn]; 60 61 // void dfs(int x, int pre, int oo) { 62 // if(head[x] > cnt || fa[fid(x)] != oo) { 63 // return; 64 // } 65 // for ( int i = head[x]; i; i = nxt[i] ) { 66 // int v = edge[i]; 67 // if(v == pre || fa[fid(x)] != oo) { 68 // continue; 69 // } 70 // if(fa[v] == fa[x]) { 71 // for(auto it : g[v]) { 72 // dfs(it, v, oo); 73 // } 74 // } 75 // else { 76 77 // int fidu = fid(x), fidv = fid(v); 78 // //printf("fa[%d]:%d fa[%d]:%d\n",x, fidu, fidv, fidv); 79 // if(fidu != oo) 80 // continue; 81 // fa[fidv] = fidu; 82 // for(auto it : g[fidv]) { 83 // g[fidu].push_back(it); 84 // } 85 // //printf("2:fa[%d]:%d fa[%d]:%d\n",x, fa[fidu], fidv, fa[fidv]); 86 // //return; 87 // } 88 // } 89 // } 90 91 vector<int> g[maxn]; 92 93 void merge(vector<int> & a, vector<int> & b) 94 { 95 if (a.size() < b.size()) swap(a, b); 96 for (auto & x: b) a.push_back(x); 97 } 98 99 100 int main() 101 { 102 scanf("%d",&t); 103 while(t--) { 104 scanf("%d %d",&n, &m); 105 int maxx = max(n, m); 106 for ( int i = 0; i <= maxx; ++i ) { 107 fa[i] = i; 108 g[i].clear(); 109 } 110 for ( int i = 1; i <= m; ++i ) { 111 int u,v; 112 scanf("%d %d",&u, &v); 113 g[u].push_back(v); 114 g[v].push_back(u); 115 } 116 int q; 117 scanf("%d",&q); 118 while (q--) { 119 int x; 120 scanf("%d", &x); 121 if (fid(x) != x) continue; 122 vector<int> tmp = g[x]; 123 g[x].clear(); 124 for (auto & v: tmp) { 125 int u = fid(v); 126 if (fid(u) == fid(x)) continue; 127 merge(g[x], g[u]); 128 fa[fid(u)] = fid(x); 129 } 130 } 131 // for ( int i = 0; i <= n - 1; ++i ) { 132 // for(auto it : g[i]) { 133 // cout << it << ' '; 134 // } 135 // puts(""); 136 // } 137 for ( int i = 0; i <= n - 1; ++i ) { 138 printf("%d ",fid(i)); 139 } 140 puts(""); 141 } 142 return 0; 143 }