solution:
图论 + 博弈论。
我们称操作前两个棋子间距离为偶数的一方为 猎人 ,不难发现 猎人 只会 win 或者 draw。这是因为终止状态中棋子的距离为 0 0 0 ,而 猎人 操作后一定是奇数,所以不可能走到对方的棋子上。当然要特判 猎人 一条边都走不到的情况。
考虑将图中所有的红色边都删除,形成若干连通块。将猎人连通块外的节点设为 1 1 1 。我们从猎人开始搜索,并记录下到达当前节点的最小步数。然后从猎物开始搜索,当且仅当当前步数小于所标记步数或当前点权值为 1 1 1 时这个点可以扩展,如果遍历到一个权值为 1 1 1 的出口并且这个点有后续连接的权值为 1 1 1 的点,则形成平局;否则无法逃脱。
一波剧烈恶心讨论。
- 若 a a a 先手没有地方可走,输出 Marin ;
- 若 b b b 没有合法出边,输出 Paula;
- 若 L o s e Lose Lose 能走到权值为 1 1 1 的点,并且这个点有后续连接的权值为 1 1 1 的点(这类节点可以预处理),输出 Magenta ;
- 否则输出 Win==a?Marin:Paula。
很考验耐性。。
时间复杂度 O ( n ) O(n) O(n) 。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
#define PII pair<int,int>
using namespace std;
const int mx = 1e5 + 5;
int n, a, b, Win, Lose, vis[mx], vis2[mx], fa[mx], dis[mx], l, cnt, cnt2, res;
char op[10];
vector<PII> g[mx];
void dfs(int u, int f) {
fa[u] = f;
for (auto v : g[u]) {
if (v.first == f)
continue;
dfs(v.first, u);
}
}
void dfs2(int u, int fa, int step) {
dis[u] = step, cnt++;
vis[u] = 1;
for (auto v : g[u]) {
if (v.first == fa || v.second == Win)
continue;
dfs2(v.first, u, step + 1);
}
}
void dfs3(int u, int fa, int step) {
if (vis2[u]) {
printf("Magenta");
exit(0);
}
for (auto v : g[u]) {
if (v.first == fa || v.second == Lose)
continue;
if (step + 1 - (Lose == a) < dis[v.first]) {
dfs3(v.first, u, step + 1);
}
}
}
void dfs4(int u, int fa) {
cnt++;
for (auto v : g[u]) {
if (v.first == fa || v.first == b || v.second == a)
continue;
dfs4(v.first, u);
}
}
void dfs5(int u, int fa) {
cnt2++;
for (auto v : g[u]) {
if (v.first == fa || v.second == b)
continue;
dfs5(v.first, u);
}
}
signed main() {
// freopen("data.in","r",stdin);
scanf("%d%d%d", &n, &a, &b);
for (int i = 1; i < n; i++) {
int u, v, w;
scanf("%d%d%s", &u, &v, op);
if (op[0] == 'c')
w = a;
else if (op[0] == 'p')
w = b;
else
w = 0;
g[u].push_back(make_pair(v, w));
g[v].push_back(make_pair(u, w));
}
dfs(1, 0);
for (int i = a; i; i = fa[i]) {
vis[i] = 1;
dis[fa[i]] = dis[i] + 1;
}
if (vis[b]) {
l = dis[b];
} else {
for (int i = b; i; i = fa[i]) {
if (vis[fa[i]]) {
l = dis[fa[i]] + dis[i] + 1;
break;
}
dis[fa[i]] = dis[i] + 1;
}
}
Win = (l & 1) ? b : a, Lose = (l & 1) ? a : b;
for (int i = 1; i <= n; i++)
dis[i] = INF, vis[i] = 0;
dfs4(a, 0);
if (cnt == 1) {
printf("Marin");
return 0;
}
dfs5(b, 0);
if (cnt2 == 1) {
printf("Paula");
return 0;
}
// printf("%d %d\n",Win,Lose);
dfs2(Win, 0, 0);
for (int i = 1; i <= n; i++) {
if (vis[i])
continue;
for (auto u : g[i]) {
if (!vis[u.first] && u.second != Lose) {
vis2[i] = 1;
break;
}
}
}
dfs3(Lose, 0, 0);
printf("%s", (Win == a) ? "Paula" : "Marin");
}