【CodeChef】Adjacent Leaves
阿新 • • 發佈:2018-12-09
【題目連結】
【思路要點】
- 首先考慮一種 處理一個詢問的方法,我們以 為根,進行 。
- 我們稱一個存在關鍵葉子的子樹為“滿的”,當且僅當該子樹中葉子結點的數量等於關鍵葉子的數量,稱一個子樹為“不滿的”,當且僅當該子樹中存在關鍵葉子
,並且它不是滿的。- 若一個點 存在三個或以上不滿的子樹,那麼顯然我們不可能將其安排至合法,因此,我們稱點
是不合法的。- 若一個點 子樹內不存在不合法的點,並且 存在恰好兩個不滿的子樹,那麼我們必須將這兩個子樹安排在開頭和結尾,即將其中一個的關鍵葉子安排為最後訪問的一系列葉子,將另一個的關鍵葉子安排為最先訪問的一系列葉子。如此一來,我們不可能將點 子樹內的關鍵葉子安排為最先或是最後訪問,因此我們要求所有的關鍵葉子都必須在點 的子樹中出現,否則,我們同樣認為 是不合法的。
- 若一個點 子樹內不存在不合法的點,並且 存在不足兩個不滿的子樹,我們一定可以將點 子樹內的關鍵葉子安排為最先或是最後訪問,因此這樣的點 始終合法。
- 答案為 當且僅當存在不合法的點。
- 上述計算過程可以通過構建虛樹進行優化,程式碼細節不再贅述。
- 時間複雜度 。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; const int MAXLOG = 21; 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(""); } bool ans, mark[MAXN]; int timer, size[MAXN], depth[MAXN], dfn[MAXN], rit[MAXN]; int root, m, n, t, all, father[MAXN][MAXLOG], sum[MAXN], cnt[MAXN]; vector <int> a[MAXN], b[MAXN]; int lca(int x, int y) { if (depth[x] < depth[y]) swap(x, y); for (int i = MAXLOG - 1; i >= 0; i--) if (depth[father[x][i]] >= depth[y]) x = father[x][i]; if (x == y) return x; for (int i = MAXLOG - 1; i >= 0; i--) if (father[x][i] != father[y][i]) { x = father[x][i]; y = father[y][i]; } return father[x][0]; } int get(int x, int y) { int z = lca(x, y); if (x != z) return father[x][0]; for (int i = MAXLOG - 1; i >= 0; i--) if (depth[father[y][i]] > depth[x]) y = father[y][i]; return y; } int calcsize(int x) { if (dfn[root] >= dfn[x] && dfn[root] <= rit[x]) return sum[1] - sum[get(x, root)]; else return sum[x]; } void work(int pos, int fa) { cnt[pos] = mark[pos]; int notfull = 0; for (auto x : b[pos]) if (x != fa) { work(x, pos); int y = get(pos, x); notfull += cnt[x] && (calcsize(y) != cnt[x]); cnt[pos] += cnt[x]; } if (notfull >= 3) ans = false; else if (notfull == 2) ans &= cnt[pos] == all; } void dfs(int pos, int fa) { size[pos] = 1; sum[pos] = a[pos].size() == 1; dfn[pos] = ++timer; depth[pos] = depth[fa] + 1; father[pos][0] = fa; for (int i = 1; i < MAXLOG; i++) father[pos][i] = father[father[pos][i - 1]][i - 1]; for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != fa) { dfs(a[pos][i], pos); sum[pos] += sum[a[pos][i]]; size[pos] += size[a[pos][i]]; } rit[pos] = timer; } bool cmp(int x, int y) { return dfn[x] < dfn[y]; } int main() { read(n), read(t); for (int i = 1; i <= n - 1; i++) { int x, y; read(x), read(y); a[x].push_back(y); a[y].push_back(x); } dfs(1, 0); while (t--) { read(root), read(m); static int q[MAXN]; for (int i = 1; i <= m; i++) { read(q[i]); mark[q[i]] = true; } q[++m] = root; sort(q + 1, q + m + 1, cmp); int cnt = 0, top = 0, s = 1; static int Stack[MAXN], used[MAXN]; if (q[1] == 1) s = 2; Stack[1] = 1; top = 1; used[1] = 1; cnt = 1; for (int i = s; i <= m; i++) { int Lca = lca(Stack[top], q[i]); if (Lca == Stack[top]) { Stack[++top] = q[i]; continue; } while (dfn[Lca] < dfn[Stack[top - 1]]) { b[Stack[top - 1]].push_back(Stack[top]); b[Stack[top]].push_back(Stack[top - 1]); used[++cnt] = Stack[top--]; } if (Lca == Stack[top - 1]) { b[Stack[top - 1]].push_back(Stack[top]); b[Stack[top]].push_back(Stack[top - 1]); used[++cnt] = Stack[top--]; Stack[++top] = q[i]; } else { b[Lca].push_back(Stack[top]); b[Stack[top]].push_back(Lca); used[++cnt] = Stack[top--]; Stack[++top] = Lca; Stack[++top] = q[i]; } } while (top >= 2) { b[Stack[top - 1]].push_back(Stack[top]); b[Stack[top]].push_back(Stack[top - 1]); used[++cnt] = Stack[top--]; } ans = true, all = m - 1; work(root, 0); if (ans) puts("YES"); else puts("NO"); for (int i = 1; i <= m; i++) mark[q[i]] = false; for (int i = 1; i <= cnt; i++) b[used[i]].clear(); } return 0; }