AtCoder Regular Contest 143 E Reversi

AtCoder 传送门

洛谷传送门

翻转一个点会把它相邻的点全部翻转,因此先从叶子开始自下而上考虑。不难发现,如果这个叶子是白色,那么它一定比它的父亲先翻转(否则它就翻不了了);而对于黑色的叶子,它一定比它的父亲后翻转。经过一波操作,我们得到了所有叶子的父亲的颜色。此时就可以把它们当作叶子处理,因为那些还没被删的叶子暂时影响不了它们。

经过模拟我们得到了树根的颜色。显然如果此时树根是黑点就无解,否则就自上而下操作。

这样我们发现父子之间的操作顺序可以确定,并且它们是充要的。建出 DAG 后跑拓扑排序即可求出字典序最小的解。

code
/*

p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;

int n, a[maxn], ind[maxn];
char s[maxn];
vector<int> G[maxn], T[maxn];

void dfs(int u, int fa) {
	a[u] = (s[u] == 'W');
	for (int v : G[u]) {
		if (v == fa) {
			continue;
		}
		dfs(v, u);
		a[u] ^= a[v];
		if (a[v]) {
			T[v].pb(u);
			++ind[u];
		} else {
			T[u].pb(v);
			++ind[v];
		}
	}
}

void solve() {
	scanf("%d", &n);
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		G[u].pb(v);
		G[v].pb(u);
	}
	scanf("%s", s + 1);
	dfs(1, -1);
	if (!a[1]) {
		puts("-1");
		return;
	}
	priority_queue< int, vector<int>, greater<int> > pq;
	for (int i = 1; i <= n; ++i) {
		if (!ind[i]) {
			pq.push(i);
		}
	}
	while (pq.size()) {
		int u = pq.top();
		pq.pop();
		printf("%d ", u);
		for (int v : T[u]) {
			if (!(--ind[v])) {
				pq.push(v);
			}
		}
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2022-12-14 18:46  zltzlt  阅读(15)  评论(0编辑  收藏  举报