xsy2468. Game

AliceBob 在一棵 n 个节点的树上玩游戏,每个节点初始要么为黑色要么为白色。
Alice 先手,轮流选择一个白色点 v,将路径 (1,v) 全部染成黑色。最后不能操作的人为输。
计算 Alice 是否必胜以及所有必胜可能的第一步节点的选择。
1n105


考虑一条路径 (1,v) 被染黑后的局面相当于被分成若干个子游戏,可以想到用 SG 函数来处理。

dpu 表示以 u 为根的子树的 SG 函数值,fu,i 表示以 u 为根的子树内,操作 (u,i) 后的 SG 函数值,sumu=isonudpi,则有

{fu,u=sumufu,i=dpvsumufv,i(vsonuisubtreev)dpu=mex{fu,i(isubtreeu)}

O(n2) 可以直接求出这些值。

如何加速?这里需要一个数据结构来支持以下操作:

  • 求出子树内所有 fmex
  • 将数据结构内的数据都异或上 x
  • 将子树内的所有 f 并到当前点。

可以用 01trie 来进行这些操作,合并类似于线段树合并即可,总时间复杂度 O(nlogn)

#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;
}
posted @   Samsara-soul  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示