ICode9

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

题解 SP11414 【COT3 - Combat on a tree】

2020-09-17 20:00:22  阅读:198  来源: 互联网

标签:ch return cov int 题解 tree text SG SP11414


发现本题为公平组合游戏,因此考虑用 \(\text{SG}\) 函数来解决。

设 \(\text{SG}(x)\) 为以 \(x\) 为根的子树的 \(\text{SG}\) 值。对于点 \(x\),可以枚举其子树内的每一个白点,删去该点到 \(x\) 的所有点,然后以 \(x\) 为根的子树会分裂为一个森林,也就是 \(x\) 状态可以转移到这个森林的状态,一个森林的 \(\text{SG}\) 值为每棵树的 \(\text{SG}\) 值异或和。\(\text{SG}(x)\) 即为子树内所有白点删去后形成的森林对应的 \(\text{SG}\) 值取 \(\text{mex}\)。

考虑用数据结构来优化这个过程,每个节点上都用一个 \(01\ Trie\) 来维护其子树内所有白点删去后对应的森林的 \(\text{SG}\) 值。设 \(y\) 为 \(x\) 的一个儿子,那么 \(y\) 对应的 \(01\ Trie\) 中维护的信息还需再异或上 \(x\) 其他儿子的 \(\text{SG}\) 值的异或和才是其正确的信息。整体异或一个值可以用打标记,交换左右儿子来实现。加上 \(y\) 的贡献即为将 \(y\) 对应的 \(01\ Trie\) 合并到 \(x\) 上。

最后再 \(dfs\) 一遍,若一个点的后继状态为必败状态,则该点可以作为第一步选的点。

#include<bits/stdc++.h>
#define maxn 200010
#define maxm 4000010
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,tot,cnt;
int c[maxn],sg[maxn],ans[maxn],rt[maxn],ch[maxm][2],tag[maxm];
bool cov[maxm];
struct edge
{
    int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
    e[++edge_cnt]={to,head[from]},head[from]=edge_cnt;
}
void pushtag(int p,int k,int x)
{
    if(k==-1) return;
    if(x>>k&1) swap(ch[p][0],ch[p][1]);
    tag[p]^=x;
}
void pushdown(int p,int k)
{
    if(!tag[p]) return;
    pushtag(ch[p][0],k-1,tag[p]),pushtag(ch[p][1],k-1,tag[p]),tag[p]=0;
}
void insert(int &p,int k,int x)
{
    if(!p) p=++tot;
    if(k==-1)
    {
        cov[p]=true;
        return;
    }
    insert(ch[p][x>>k&1],k-1,x);
    cov[p]=cov[ch[p][0]]&cov[ch[p][1]];
}
int merge(int x,int y,int k)
{
    if(!x||!y) return x+y;
    if(k==-1)
    {
        cov[x]|=cov[y];
        return x;
    }
    pushdown(x,k),pushdown(y,k);
    ch[x][0]=merge(ch[x][0],ch[y][0],k-1);
    ch[x][1]=merge(ch[x][1],ch[y][1],k-1);
    cov[x]=cov[ch[x][0]]&cov[ch[x][1]];
    return x;
}
int mex(int p,int k)
{
    if(!p||k==-1) return 0;
    pushdown(p,k);
    if(cov[ch[p][0]]) return (1<<k)|mex(ch[p][1],k-1);
    return mex(ch[p][0],k-1);
}
void dfs_get(int x,int fa)
{
    int v=0;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(y==fa) continue;
        dfs_get(y,x),v^=sg[y];
    }
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(y==fa) continue;
        pushtag(rt[y],20,v^sg[y]);
        rt[x]=merge(rt[x],rt[y],20);
    }
    if(!c[x]) insert(rt[x],20,v);
    sg[x]=mex(rt[x],20);
}
void dfs_ans(int x,int fa,int v)
{
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(y==fa) continue;
        v^=sg[y];
    }
    if(!v&&!c[x]) ans[++cnt]=x;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(y==fa) continue;
        dfs_ans(y,x,v^sg[y]);
    }
}
int main()
{
    read(n);
    for(int i=1;i<=n;++i) read(c[i]);
    for(int i=1;i<n;++i)
    {
        int x,y;
        read(x),read(y);
        add(x,y),add(y,x);
    }
    dfs_get(1,0);
    if(!sg[1]) puts("-1");
    else
    {
        dfs_ans(1,0,0),sort(ans+1,ans+cnt+1);
        for(int i=1;i<=cnt;++i) printf("%d ",ans[i]);
    }
    return 0;
}

标签:ch,return,cov,int,题解,tree,text,SG,SP11414
来源: https://www.cnblogs.com/lhm-/p/13687252.html

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

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

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

ICode9版权所有