[题解] AGC010F Tree Game

posted on 2025-01-02 11:32:52 | under | source

比较弱的一道树上博弈题,我这种博弈菜鸟都能想出来。所以记一下题解的做法。

\(f_i\) 为从 \(i\) 开始,只在 \(i\) 子树博弈时,先手是否必胜。为何这样设计?假如跳出了子树,那么不难发现,重新回到子树时,先后手顺序和原来不会发生改变,所以可以把该子树单独看成一个游戏,那么子树内外互不影响。

考虑转移,首先不可能走到必胜点,这样会困在该子树内而白给;假如是必败点,那么后手只能不断移回根,不让先手在 \(v\) 子树走必胜策略。假如 \(a_v<a_u\) 那么拼不过先手就会输,所以充分条件是存在一个必败点满足 \(a_v<a_u\)。同时是必要的,因为若每个必败点都 \(a_v\ge a_u\),那么先手拼不过后手,只能输掉。

代码

#include<bits/stdc++.h>
using namespace std;

const int N = 3e3 + 5;
int n, a[N], u, v, ans;
bool f[N];
vector<int> to[N];

inline void dfs(int u, int fa){
	f[u] = false;
	bool fl = true;
	for(auto v : to[u]) fl &= (a[v] >= a[u]);
	if(fl) return ;
	for(auto v : to[u]) if(a[v] < a[u]) dfs(v, u), f[u] |= !f[v];
}
signed main(){
	cin >> n;
	for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	for(int i = 1; i < n; ++i) scanf("%d%d", &u, &v), to[u].push_back(v), to[v].push_back(u);  
	for(int i = 1; i <= n; ++i){
		dfs(i, 0);
		if(f[i]) printf("%d ", i);
	}
	return 0;
}
posted @ 2026-01-13 11:21  Zwi  阅读(0)  评论(0)    收藏  举报