#阶梯NIM,树形dp#CF1498F Christmas Game
题目
Alice 和 Bob 在一棵 \(n\) 个点的树上玩游戏,第 \(i\) 个节点上有 \(a_i\) 个石子,
每轮可以选择一个深度至少为 \(k\) 的节点并移动任意多石子到其 \(k\) 级祖先处,对每个结点询问如果将其作为根谁会赢。
分析
设\(dp[x][d]\)表示以 \(x\) 为根的子树离\(x\)的距离\(\bmod 2k\) 为 \(d\) 的SG值
由于先手移动偶数层后手可以用同样的方式移上去所以只需要考虑奇数层的SG值,
直接二次扫描换根即可
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011; struct node{int y,next;}e[N<<1];
int dp[N][40],n,m,ans[N],a[N],et=1,as[N],f[40];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void dfs1(int x,int fa){
dp[x][0]=a[x];
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa){
dfs1(e[i].y,x);
for (rr int j=0;j<m;++j)
dp[x][(j+1)%m]^=dp[e[i].y][j];
}
}
inline void dfs2(int x,int fa){
if (fa){
for (rr int j=0;j<m;++j) f[(j+1)%m]=dp[fa][(j+1)%m]^dp[x][j];
for (rr int j=0;j<m;++j) dp[x][(j+1)%m]^=f[j];
}
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs2(e[i].y,x);
}
signed main(){
n=iut(),m=iut()<<1;
for (rr int i=1;i<n;++i){
rr int x=iut(),y=iut();
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
for (rr int i=1;i<=n;++i) a[i]=iut();
dfs1(1,0),dfs2(1,0);
for (rr int i=1;i<=n;++i){
for (rr int j=m/2;j<m;++j) ans[i]^=dp[i][j];
putchar((ans[i]>0)+48),putchar(32);
}
return 0;
}