ps:因为我也是这两天学的树上博弈,可能有的地方描述不是很准确,如有错误之处,欢迎指出
前置知识:green博弈:给定一棵树,两人轮流进行删边,删除改边后,由改边与根节点联通的子树也随之删除,当无边可删者输。
green博弈解法:详细推导过程点这里,把每一条树链拿出来,不难发现在这条链上选边删除,类似于取石子nim游戏中的取走一定数量的石子,而且有SG[x]=他的子节点数量,所以对叶子节点来说SG[x]=0,而叶子结点的父节点的SG[y]=SG[x]+1,上述讨论的是单链,现在对整棵树讨论,如果是叶子节点,则SG[x]=0;然后从树的最底层一层一层往上走,不断更新SG[y],SG[y]^=(SG[x]+1)(SG定理)
但是上面讨论的是树的权值都为1的情况下,下面开始推导当权值不为1的情况下的SG,这里需要用到SG函数的定义,即SG(u)=mex{SG(v)},u→v ,推导思路来源,上面的链接里有带图的推理过程,但本人画图属实菜鸡,推导过程可以看链接里的,我这里自己推给自己看
简单推导:
定义dp[x][y]为AB边的权值为x,y是与B相连的树链的长度(即SG[B]=y)以时节点A的SG值;
①当x=0时,即A就是根节点,此情况下无法操作,既有SG[A]=0,dp[0][y]=0;
②当x=1时,此时就是裸green博弈,则dp[1][x]=x+1;
当x==1时
dp[1][y]=SG[y]+1
当x=2时
dp[2][0]=mex(dp[1][0])=mex(1)=0=SG[B];
dp[2][1]=mex(dp[1][1],dp[2][0])=mex(2,0)=1=SG[B];
dp[2][2]=mex(dp[1][2],dp[2][0],dp[2][1])=mex(3,0,1)=2=SG[B]…
…
…
dp[2][y]=mex(dp[1][y],dp[2,0],dp[2][1]…dp[2][y-1])=mex(y+1,0,1,…y-1)=y=SG[B];
所以但权值为偶数时SG[A]=SG[B]
当x=3时
dp[3][0]=mex(dp[2][0])=1;
dp[3][1]=mex(dp[2][1],dp[3][0])=mex(1,1)=0;
dp[3][2]=mex(dp[2][2],dp[3][0],dp[3][1])=mex(2,1,0)=3;
…
dp[3][x]=mex(dp[2][x],dp[3][0],dp[3][1]…dp[3][x-1])=mex(x,1,0,3,2…t)(t=((x-1)&1)?x-2:x)=((x-1)&1)?x-1:x+1;
当x=…(逃)
if (val == 1) sg[from] ^= sg[to];
else sg[from]^=(sg[to]^(val%2));
小知识`x ^ 1 == (x & 1) ? x - 1 : x + 1;
好了,完事
AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<functional>
#include<vector>
using namespace std;
const int maxn = 10100;
struct edge {
int to;
int nxt;
int val;
}date[maxn];
int head[maxn];
int sg[maxn];
int cnt;
void add(int u, int v,int w) {
date[++cnt].to = v;
date[cnt].nxt = head[u];
date[cnt].val = w;
head[u] = cnt;
}
void dfs(int x,int y) {
sg[x] = 0;
for (int i = head[x]; i!=-1; i = date[i].nxt) {
int v = date[i].to;
if (v == y) continue;
dfs(v,x);
if (date[i].val == 1) sg[x] ^=(sg[v] + 1);
else sg[x] ^= (sg[v] ^ (date[i].val % 2));
}
}
int main() {
int t;
scanf("%d", &t);
for (int k = 1; k <= t; k++) {
int n;
cnt = 0;
memset(head, -1, sizeof(head));
//memset(sg, 0, sizeof(sg));
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
dfs(0, 0);
if (sg[0]) printf("Case %d: Emily\n", k);
else printf("Case %d: Jolly\n", k);
}
}