【題目鏈接】
【思路要點】
- 不妨令 ,由 ,則有 。
- 由於我們只希望有兩個導出子圖連通,因此一定是 對應的兩個子圖,換言之,我們至多可以浪費 個點。
- 任取一個圖的搜索樹,考慮找到最深的一個子樹大小 的節點 ,那麼 的每個子樹大小均 。
- 記 子樹大小爲 ,子樹中刪去 後依然與根節點連通的點數爲 ,若 ,那麼顯然可以判斷問題無解,否則,我們可以按照如下方式給出一組構造:
- 若 ,則我們要求 所在的連通塊大小爲 。我們可以先將子樹中刪去 後不與根節點連通的點加入連通塊,如果此時點數已經達到 ,則構造完成,只需要從根節點 找到相鄰的 個點即可。注意到 的每個子樹大小均 ,並且我們至多可以浪費 個點,接下來可以一個一個子樹地往連通塊里加點,直到點數達到 ,再從根節點 找到相鄰的 個點。
- 若 ,由 ,則 ,那麼我們要求 所在的連通塊大小爲 。按照相同的方法處理,即可從根節點 找到相鄰的 個點。
- 時間複雜度 。
【代碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } vector <int> a[MAXN]; pair <int, int> lim[5]; bool instack[MAXN]; int n, m, cnt, size[MAXN], ans[MAXN]; int timer, dfn[MAXN], low[MAXN]; void dfs(int pos, int col, bool down) { if (cnt == 0 || ans[pos]) return; ans[pos] = col, cnt--; for (auto x : a[pos]) if (!down || dfn[x] > dfn[pos]) dfs(x, col, down); } void tarjan(int pos, int fa) { instack[pos] = true; dfn[pos] = low[pos] = ++timer; int sum = 0; size[pos] = 1; vector <int> sons; for (auto x : a[pos]) if (dfn[x] == 0) { tarjan(x, pos); sons.push_back(x); chkmin(low[pos], low[x]); size[pos] += size[x]; if (low[x] < dfn[pos]) sum += size[x]; } else if (instack[x]) chkmin(low[pos], dfn[x]); if (size[pos] >= lim[1].first) { if (n - size[pos] + sum < lim[1].first) { for (int i = 1; i <= n; i++) printf("%d ", 0); printf("\n"); exit(0); } if (n - size[pos] + sum < lim[2].first) swap(lim[1], lim[2]); int colx = lim[1].second, coly = lim[2].second; cnt = lim[1].first, ans[pos] = colx, cnt--; for (auto x : sons) if (low[x] >= dfn[pos]) dfs(x, colx, true); for (auto x : sons) if (low[x] < dfn[pos]) dfs(x, colx, true); assert(cnt == 0); cnt = lim[2].first; dfs(1, coly, false); assert(cnt == 0); for (int i = 1; i <= n; i++) { if (ans[i] == 0) ans[i] = lim[3].second; printf("%d ", ans[i]); } printf("\n"); exit(0); } instack[pos] = false; } int main() { read(n), read(m); for (int i = 1; i <= 3; i++) { int x; read(x); lim[i] = make_pair(x, i); } sort(lim + 1, lim + 4); assert(lim[1].first + lim[2].first + lim[3].first == n); for (int i = 1; i <= m; i++) { int x, y; read(x), read(y), x++, y++; a[x].push_back(y); a[y].push_back(x); } tarjan(1, 0); assert(false); return 0; }