xsy2468. Game
和 在一棵 个节点的树上玩游戏,每个节点初始要么为黑色要么为白色。
先手,轮流选择一个白色点 v,将路径 全部染成黑色。最后不能操作的人为输。
计算 是否必胜以及所有必胜可能的第一步节点的选择。
。
考虑一条路径 被染黑后的局面相当于被分成若干个子游戏,可以想到用 函数来处理。
设 表示以 为根的子树的 函数值, 表示以 为根的子树内,操作 后的 函数值,,则有
可以直接求出这些值。
如何加速?这里需要一个数据结构来支持以下操作:
- 求出子树内所有 的 。
- 将数据结构内的数据都异或上 。
- 将子树内的所有 并到当前点。
可以用 来进行这些操作,合并类似于线段树合并即可,总时间复杂度 。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,L=16;
struct Node{int sz,son[2],tag;}tree[N<<2];
int n,flag,tot,col[N],suc[N],sum[N],dp[N],rt[N];vector<int>G[N];
inline void pushup(int x){
tree[x].sz=tree[tree[x].son[0]].sz+tree[tree[x].son[1]].sz;
}
inline void pushdown(int x,int at){
if(tree[x].tag>>at&1)swap(tree[x].son[0],tree[x].son[1]);
tree[x].tag&=((1<<at)-1);
tree[tree[x].son[0]].tag^=tree[x].tag;
tree[tree[x].son[1]].tag^=tree[x].tag;
tree[x].tag=0;
}
inline void insert(int &x,int at){
if(!x)x=++tot;
if(!~at){tree[x].sz=1;return;}
pushdown(x,at);
insert(tree[x].son[0],at-1);
pushup(x);
}
inline int merge(int rx,int ry,int at){
if(!rx||!ry)return rx+ry;
pushdown(rx,at),pushdown(ry,at);
if(!~at)return rx;
tree[rx].son[0]=merge(tree[rx].son[0],tree[ry].son[0],at-1);
tree[rx].son[1]=merge(tree[rx].son[1],tree[ry].son[1],at-1);
return pushup(rx),rx;
}
inline int query_mex(int x,int ans,int at){
if(!~at)return ans;
pushdown(x,at);
if(tree[tree[x].son[0]].sz<(1<<at))return query_mex(tree[x].son[0],ans,at-1);
return query_mex(tree[x].son[1],ans|(1<<at),at-1);
}
inline void op_xor(int x,int t){tree[x].tag^=t;}
inline void dfs(int x,int fa){
int fl=0;
for(auto y:G[x])if(y^fa){
fl=1,dfs(y,x),sum[x]^=dp[y];
rt[x]=merge(rt[x],rt[y],L);
}
if(fl){
if(!col[x])insert(rt[x],L);
op_xor(rt[x],sum[x]);
dp[x]=query_mex(rt[x],0,L);
op_xor(rt[x],dp[x]);
}
else if(!col[x])dp[x]=1,insert(rt[x],L),op_xor(rt[x],dp[x]);
}
inline void solve(int x,int fa,int val){
if(!val&&!col[x])suc[x]=1;
for(auto y:G[x])if(y^fa)solve(y,x,val^sum[y]^dp[y]);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",col+i);
for(int i=1,x,y;i<n;++i){
scanf("%d%d",&x,&y);
G[x].emplace_back(y),G[y].emplace_back(x);
}
dfs(1,0),solve(1,0,sum[1]);
for(int i=1;i<=n;++i)if(suc[i])printf("%d\n",i),flag=1;
if(!flag)puts("-1");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】