ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

xsy2468. Game

2022-06-08 19:34:14  阅读:139  来源: 互联网

标签:sz xsy2468 int text tree son Game dp


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


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

设 \(dp_{u}\) 表示以 \(u\) 为根的子树的 \(\text{SG}\) 函数值,\(f_{u,i}\) 表示以 \(u\) 为根的子树内,操作 \((u,i)\) 后的 \(\text{SG}\) 函数值,\(sum_{u}=\bigoplus\limits_{i\in \text{son}_{u}} dp_{i}\),则有

\[\left\{\begin{matrix} f_{u,u}=sum_{u}\\ f_{u,i}=dp_{v}\oplus sum_{u}\oplus f_{v,i}\quad (v\in \text{son}_{u}\cap i\in \text{subtree}_{v})\\ dp_{u}=\text{mex}\{f_{u,i}\mid(i\in \text{subtree}_{u})\}\\ \end{matrix}\right. \]

\(O(n^2)\) 可以直接求出这些值。

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

  • 求出子树内所有 \(f\) 的 \(\text{mex}\)。
  • 将数据结构内的数据都异或上 \(x\)。
  • 将子树内的所有 \(f\) 并到当前点。

可以用 \(\text{01trie}\) 来进行这些操作,合并类似于线段树合并即可,总时间复杂度 \(O(n\log n)\)。

#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;
}

标签:sz,xsy2468,int,text,tree,son,Game,dp
来源: https://www.cnblogs.com/Samsara-soul/p/16356895.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有