P9039 [PA2021] Drzewo czerwono-czarne

cxqghzj·2024-04-11 20:31·21 次阅读

P9039 [PA2021] Drzewo czerwono-czarne

题意#

给定一棵树,最初每个节点有一个颜色 0/1

给定一个结束序列,你需要判断是否可以通过任意次数的下列操作,使树的每个节点的颜色与该序列一一对应。

  • 选择一条边 uv,使 uv 都覆盖上 u 的颜色。

Sol#

其实是弱智分讨题。

首先考虑链的情况,注意到一个显然的事情。

我们需要对于链的颜色段数进行讨论,显然每一段可以向左右不断延申,也可以将某一段给吞掉。

所以颜色段数显然不会变多,特判掉第一段,直接判掉即可。

不难通过打个暴力、集中注意力、意淫,等方式,注意到若该树不是一条链,显然有解。

考虑证明。

首先先判掉一些显然的东西:

  • 开始与结束相等
  • 开始序列只有一种颜色
  • 结束序列没有相同的边

不难注意到对于一个度数为 3 的点 u

考虑将 u 转到根上面。

发现对于任意时刻,对于 u 的所有儿子 v,都可以在其中两个点上,分别储存两种颜色。

此时,我们不需要关心 u 的颜色,可以先将另一个儿子的子树暴力染掉。

然后再使用另一个儿子储存一种颜色,去染下一个儿子。

最后,使用最后一个儿子,染掉 u 即可。

Code#

Copy
#include <iostream> #include <algorithm> #include <cstdio> #include <array> #include <assert.h> using namespace std; #ifdef ONLINE_JUDGE /* #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) */ /* char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; */ #endif int read() { int p = 0, flg = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') flg = -1; c = getchar(); } while (c >= '0' && c <= '9') { p = p * 10 + c - '0'; c = getchar(); } return p * flg; } void write(int x) { if (x < 0) { x = -x; putchar('-'); } if (x > 9) { write(x / 10); } putchar(x % 10 + '0'); } bool _stmer; const int N = 1e5 + 5, M = 2e5 + 5; namespace G { array <int, N> fir; array <int, M> nex, to; int cnt = 1; void add(int x, int y) { cnt++; nex[cnt] = fir[x]; to[cnt] = y; fir[x] = cnt; } } //namespace G string s1, s2; char strbuf[N]; array <int, N> fa, deg; void dfs(int x, int &tp1, int &tp2) { if (s1[x] != s1[fa[x]]) tp1++; if (s2[x] != s2[fa[x]]) tp2++; for (int i = G::fir[x]; i; i = G::nex[i]) if (fa[x] != G::to[i]) fa[G::to[i]] = x, dfs(G::to[i], tp1, tp2); } void solve() { int n = read(); G::cnt = 1; scanf("%s", strbuf), s1 = strbuf; scanf("%s", strbuf), s2 = strbuf; s1 = " " + s1, s2 = " " + s2; bool flg1 = 1, flg2 = 1; for (int i = 1; i <= n; i++) deg[i] = fa[i] = G::fir[i] = 0; for (int i = 1; i <= n; i++) flg1 &= s1[i] == s2[i], flg2 &= i == 1 || s1[i] == s1[i - 1]; int rt = 0; bool flg3 = 1, flg4 = 0; for (int i = 2; i <= n; i++) { int x = read(), y = read(); G::add(x, y), G::add(y, x); deg[x]++, deg[y]++, flg3 &= !(s2[x] == s2[y]); } for (int i = 1; i <= n; i++) { if (deg[i] > 2) flg4 = 1; if (deg[i] == 1) rt = i; } if (flg1) return (void)puts("TAK"); if (flg2) return (void)puts("NIE"); if (flg3) return (void)puts("NIE"); if (flg4) return (void)puts("TAK"); assert(rt); int tp1 = 0, tp2 = 0; dfs(rt, tp1, tp2); if (s1[rt] != s2[rt]) tp1--; if (tp1 >= tp2) return (void)puts("TAK"); else return (void)puts("NIE"); } bool _edmer; int main() { cerr <<(&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n"; int T = read(); while (T--) solve(); return 0; }
posted @   cxqghzj  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
目录