1. 程式人生 > >【CodeChef】Adjacent Leaves

【CodeChef】Adjacent Leaves

【題目連結】

【思路要點】

  • 首先考慮一種 O ( N ) O(N) 處理一個詢問的方法,我們以 R
    R
    為根,進行 d f s dfs
  • 我們稱一個存在關鍵葉子的子樹為“滿的”,當且僅當該子樹中葉子結點的數量等於關鍵葉子的數量,稱一個子樹為“不滿的”,當且僅當該子樹中存在關鍵葉子
    ,並且它不是滿的。
  • 若一個點 x x 存在三個或以上不滿的子樹,那麼顯然我們不可能將其安排至合法,因此,我們稱點 x x
    是不合法的。
  • 若一個點 x x 子樹內不存在不合法的點,並且 x x 存在恰好兩個不滿的子樹,那麼我們必須將這兩個子樹安排在開頭和結尾,即將其中一個的關鍵葉子安排為最後訪問的一系列葉子,將另一個的關鍵葉子安排為最先訪問的一系列葉子。如此一來,我們不可能將點 x x 子樹內的關鍵葉子安排為最先或是最後訪問,因此我們要求所有的關鍵葉子都必須在點 x x 的子樹中出現,否則,我們同樣認為 x x 是不合法的。
  • 若一個點 x x 子樹內不存在不合法的點,並且 x x 存在不足兩個不滿的子樹,我們一定可以將點 x x 子樹內的關鍵葉子安排為最先或是最後訪問,因此這樣的點 x x 始終合法。
  • 答案為 N O NO 當且僅當存在不合法的點。
  • 上述計算過程可以通過構建虛樹進行優化,程式碼細節不再贅述。
  • 時間複雜度 O ( N L o g N + K i L o g N ) O(NLogN+\sum K_iLogN)

【程式碼】

#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;
}