- 题意
给定一颗树,对于每个节点有一个颜色(白色或者黑色),对于一个操作:选择一个叶子节点,对于从叶子节点到根节点路径上的所有颜色反转(黑变白,白变黑)。
让你求出使用任意次操作后,整个树上黑色节点最多有多少个。 - 思路
对于每个节点在最终状态有两种结果,一个是不变,一个是反转颜色。如果颜色反转,则在这个节点的子树里,我们选择了奇数个叶子节点进行操作(显然,偶数次的操作经过一个节点不会改变该节点颜色)。这时我们可以设置f[N][2]表示对于每个节点,在其子树选择叶子节点的奇偶性可以获得的最大黑色数量。 - 代码
#include<bits/stdc++.h> using LL = long long; constexpr int N = 2e5 + 7; constexpr int M = 1e6 + 7; constexpr int MOD = 1e9 + 7; constexpr int mod = 998244353; constexpr int inf = 0x3f3f3f3f; constexpr LL INF = 0x3f3f3f3f3f3f3f3f; std::vector<int>e[N]; int f[N][2]; int a[N], in[N]; int n; struct CNM { int ji, ou; bool operator < (const CNM &a) const { return (ji - ou) > (a.ji - a.ou); } }; void dfs(int u, int fa) { if (u != 1 && in[u] == 1) { f[u][0] = a[u]; f[u][1] = (a[u] ^ 1); return; } std::vector<CNM> t; bool ok = true; for (int v : e[u]) { if (v == fa) continue; dfs(v, u); if (f[v][0] != -1 && f[v][1] != -1)ok = true, t.push_back({f[v][1], f[v][0]}); } if (!ok) return; std::sort(t.begin(), t.end()); int res = 0; for (auto [x, y] : t) res += y; int cnt = 0; int ji = 0, ou = res; for (auto [x, y] : t) { cnt ++; res += x; res -= y; if (cnt & 1) ji = std::max(ji, res); else ou = std::max(ou, res); } f[u][1] = (a[u] ^ 1) + ji; f[u][0] = a[u] + ou; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cin >> n; for (int i = 1; i <= n; ++i) f[i][1] = -1, f[i][0] = -1; for (int i = 1; i <= n; ++i) std::cin >> a[i]; for (int i = 1, u, v; i <= n - 1; ++i) { std::cin >> u >> v; e[u].push_back(v); e[v].push_back(u); in[u] ++; in[v] ++; } dfs(1, 0); std::cout << std::max(f[1][1], f[1][0]) << '\n'; return 0; }
- Universal Ookayama Problem April Stageuniversal ookayama problem april universal stage the 2nd universal qingdao stage the universal stage 6555 good universal contest nanjing stage universal shenyang stage the universal northern stage good universal stage hefei the universal binjiang stage the universal okayama stage the