1. 程式人生 > 實用技巧 >牛客多校3-Operating on a Graph【dsu】

牛客多校3-Operating on a Graph【dsu】

題意:

  給定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 }