整天鬼畜題搞搞,感覺葯丸……
這種題出到xjoi模擬題里,太神了……
這題的核心在於分割Cograph,嘗試把Cograph的合成過程給求出來。
我們將這張圖中的邊定為黑邊,在這張圖的補圖中出現的邊定為白邊,則黑邊和白邊構成了一個完全圖。
1.如果當前這張圖的黑邊是不聯通的,那么可以檢查所有的黑邊構成的聯通塊是不是Cograph,如果都是Cograph,則原圖也為Cograph
2.如果當前這張圖的白邊是不聯通的,那么可以檢查所有的白邊構成的聯通塊是不是Cograph,如果都是Cograph,則原圖也為Cograph
3.如果當前這張圖中的白邊黑邊都是聯通的,直接返回該圖不是Cograph
這樣做顯然是正確的,但是時間復雜度太高了,每次划分的復雜度是\(O(m)\)的,由於白邊有\(O(n^2)\)條,因此這個做法也是\(O(n^2)\)
顯然是會爆炸的……
考慮優化這個做法,我們並不需要枚舉所有白邊,當找到一條白邊時,就將它所連接的兩個白聯通塊合並,合並次數是\(O(n)\)的
因此需要一種支持快速 合並聯通塊、查詢一個聯通塊到另一個聯通塊之間所有邊的數據結構……
這里用鏈表維護聯通塊……(為什么不用並查集?因為我要訪問該聯通塊所有的點
這樣就可以保證每次查詢的邊一定是不在當前同一個聯通塊中,
查詢的兩個點間要么是黑邊要么是白邊,黑邊只有\(O(m)\)條,由於只有\(O(n)\)次合並,因此掃到的白邊只有\(O(n)\)條,時間復雜度是\(O(n + m)\)的
這樣對於一個問題,只需要\(O(n + m)\)就可以把它變成若干個小原問題了。
由於Cograph每層的分割至少有\(O(n)\)條連接在白聯通塊之間的黑邊被刪除了,因此這樣分割的層數是\(O(min(m / n, n))\)的
總時間復雜度\(O((n + m)\sqrt{m})\)
跑的稍微有點慢啊~
#include <bits/stdc++.h> #define N 300000 using namespace std; vector <int> bi[N], bn[N]; int T, n, m; int ai[N]; int nx[N], ne[N], nl[N], tot; int vis[N], td[N], tt[N], col[N]; int tmp; void dfs1(int t, int c) { vis[t] = c; for (int i = 0; i < bi[t].size(); ++ i) if (!vis[bi[t][i]]) dfs1(bi[t][i], c); } int solve2(int t); int solve1(int t) { int nw = tmp + 1; for (int p = t; p; p = nx[p]) vis[p] = 0; for (int p = t; p; p = nx[p]) if (!vis[p]) dfs1(p, vis[p] = ++ tmp); for (int p = t; p; p = nx[p]) { if (!tt[vis[p]]) tt[vis[p]] = td[vis[p]] = p; else { nx[td[vis[p]]] = p; td[vis[p]] = p; } } for (int i = nw; i <= tmp; ++ i) { nx[td[i]] = 0; if (!solve2(tt[i])) return 0; } return 1; } set <int> S[N]; int test(int a, int b) { return S[a].count(b); } int solve2(int t) { if (nx[t] == 0) return 1; for (int p = t; p; p = nx[p]) ne[p] = nx[p], nl[p] = p; for (int p = t; p; p = ne[p]) nx[p] = 0; for (int p = t; p; p = ne[p]) { for (int a = p; a; a = nx[a]) { for (int q = ne[p], c = p; q; ) { int bo = 0; for (int b = q; b; b = nx[b]) if (!test(a, b)) { bo = 1; goto haha; } haha: if (bo) { nx[nl[p]] = q; nl[p] = nl[q]; nl[q] = 0; ne[c] = ne[q]; ne[q] = 0; q = ne[c]; } else { c = ne[c]; q = ne[q]; } } } } if (ne[t] == 0) return 0; for (int p = t; p; p = ne[p]) for (int q = p; q; q = nx[q]) col[q] = p, bn[q].clear(); for (int p = t; p; p = ne[p]) for (int q = p; q; q = nx[q]) for (int a = 0; a < bi[q].size(); ++ a) if (col[bi[q][a]] == col[q]) bn[q].push_back(bi[q][a]); for (int p = t; p; p = ne[p]) for (int q = p; q; q = nx[q]) bi[q] = bn[q]; vector <int> nls; for (int p = t; p; p = ne[p]) nls.push_back(p); for (int p = 0; p < nls.size(); ++ p) if (!solve1(nls[p])) return 0; return 1; } int main() { //freopen("C.in", "r", stdin); scanf("%d", &T); while (T --) { scanf("%d%d", &n, &m); for (int i = 1; i <= m; ++ i) { int a, b; scanf("%d%d", &a, &b); bi[a].push_back(b); S[a].insert(b); bi[b].push_back(a); S[b].insert(a); } for (int i = 1; i < n; ++ i) nx[i] = i + 1, ne[i] = 0; nx[n] = 0; if (solve1(1)) puts("TAK"); else puts("NIE"); for (int i = 1; i <= n; ++ i) bi[i].clear(), S[i].clear(); } }