题目链接


\(Description\)

给定一棵\(n\)个点的树,每个点是黑色或白色。两个人轮流操作,每次可以选一个白色的点,将它到根节点路径上的所有点染黑。不能操作的人输,求先手是否能赢。如果能,输出第一步选择哪些节点能赢。

\(n\leq10^5\)。

\(Solution\)

Orz huzecong

对于叶子节点,如果能染色,\(SG(x)=1\),否则\(=0\)。

考虑从下往上算每棵子树的\(SG\)值。设\(SG(x)\)表示\(x\)子树的\(SG\)值,\(g(x)\)表示对\(x\)这棵子树操作能得到的后继的\(SG\)值集合(只考虑\(x\)子树),那么\(SG(x)=\mathbb{mex}\{g(x)\}\)。

考虑如何计算\(g(x)\)。令\(sum[x]=sg(v_1)\ \mathbb{xor}\ sg(v_2)\ \mathbb{xor}...,\ v_i\in son[x]\)。

若\(x\)是黑点,假设这次操作选了\(v_i\)子树中的某个点,那么其它子树状态不变,\(v_i\)子树的后继状态会变成\(g(v_i)\)中的某个,所以\(g(x)=sum[x]\ \mathbb{xor}\ sg(v_i)\ \mathbb{xor}\ (g(v_i)中的某个值)\)。

把子树内每个\(g(v_i)\)整体\(\mathbb{xor}\)一个数,合并起来,就可以得到\(g(x)\)了。

若\(x\)是白点,多了一种选\(x\)的后继,选\(x\)后得到状态的\(SG\)值就是\(sum[x]\)。所以在\(g(x)\)中再插入一个\(sum[x]\)即可。

还要支持求\(\mathbb{mex}\),可以用\(01Trie\)维护。合并的时候可以启发式合并,\(O(n\log^2n)\),也可以类似线段树合并做到\(O(n\log n)\)。

对于第二问,考虑选择一个节点后局面的\(SG\)值。容易发现就是除去它到根节点路径上的点的所有点的\(SG\)值的异或和。

记\(up[x]\)表示除去\(x\)到根节点路径上的点外,所有节点的\(SG\)值异或和,那么\(up[x]=up[fa[x]]^{\wedge}sum[fa[x]]^{\wedge}SG(x)\)。选择\(x\)后\(x\)的各棵子树是独立的,局面的\(SG\)值就是\(up[x]^{\wedge}sum[x]\)(\(up\)也可以直接\(DFS\)的时候传个参)。

所以如果\(up[x]^{\wedge}sum[x]=0\),选这个点就是必胜的。

这个\(SG\)值的最大值是啥啊...

注意\(Trie\)要特判叶子的地方(尤其是Merge,注意像线段树合并一样判下叶子)(我怎么老是写错...)。


//0.11s	35M
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define Bit 16
#define gc() getchar()
#define MAXIN 500000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+5; int Enum,H[N],nxt[N<<1],to[N<<1],root[N],sg[N],sum[N],up[N];
bool col[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Trie
{
#define S N*20
#define ls son[x][0]
#define rs son[x][1]
int tot,son[S][2],tag[S];
bool full[S];
#define Update(x) full[x]=full[ls]&&full[rs]
inline void Upd(int x,int v,int dep)
{
// if(dep<0) return;
if(v>>dep&1) std::swap(ls,rs);
tag[x]^=v;
}
inline void PushDown(int x,int dep)
{
if(dep&&tag[x]) Upd(ls,tag[x],dep-1), Upd(rs,tag[x],dep-1), tag[x]=0;
}
void Insert(int &x,int v,int dep)
{
x=++tot;
if(dep<0) {full[x]=1; return;}
v>>dep&1 ? Insert(rs,v,dep-1) : Insert(ls,v,dep-1);
}
int Merge(int x,int y,int dep)
{
if(!x||!y) return x|y;
if(dep<0) return x;
PushDown(x,dep), PushDown(y,dep);
ls=Merge(ls,son[y][0],dep-1), rs=Merge(rs,son[y][1],dep-1);
Update(x); return x;
}
int Mex(int x,int dep)
{
if(!x||dep<0) return 0;
PushDown(x,dep);
return full[ls]?(1<<dep)+Mex(rs,dep-1):Mex(ls,dep-1);
}
}T; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline void AE(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void DFS1(int x,int fa)
{
if(!col[x]) T.Insert(root[x],0,Bit);
int s=0;
for(int i=H[x],v; i; i=nxt[i])
if((v=to[i])!=fa)
DFS1(v,x), s^=sg[v], T.Upd(root[v],sg[v],Bit), root[x]=T.Merge(root[x],root[v],Bit);
if(s) T.Upd(root[x],s,Bit);
sum[x]=s, sg[x]=T.Mex(root[x],Bit);
}
void DFS2(int x,int fa)
{
up[x]=up[fa]^sum[fa]^sg[x];
for(int i=H[x],v; i; i=nxt[i])
if((v=to[i])!=fa) DFS2(v,x);
} int main()
{
const int n=read();
for(int i=1; i<=n; ++i) col[i]=read();
for(int i=1; i<n; ++i) AE(read(),read());
DFS1(1,0), sum[0]=sg[1], DFS2(1,0);
bool f=0;
for(int x=1; x<=n; ++x) if(!col[x]&&!(sum[x]^up[x])) f=1, printf("%d\n",x);
if(!f) puts("-1"); return 0;
}

SPOJ COT3.Combat on a tree(博弈论 Trie合并)的更多相关文章

  1. SPOJ COT3 Combat on a tree(Trie树、线段树的合并)

    题目链接:http://www.spoj.com/problems/COT3/ Alice and Bob are playing a game on a tree of n nodes.Each n ...

  2. SPOJ COT3 - Combat on a tree

    /* 考虑直接使用暴力来算的话 SG[i]表示以i为根的子树的SG值, 然后考虑枚举删除那个子树节点, 然后求拆成的树的sg异或值, 求mex即可 复杂度三次方 然后考虑尝试 整体来做 发现对于每次子 ...

  3. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  4. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  5. Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 2588: Spoj 10628. Count on a tree Time Limit ...

  6. BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )

    Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...

  7. 【BZOJ2589】 Spoj 10707 Count on a tree II

    BZOJ2589 Spoj 10707 Count on a tree II Solution 吐槽:这道题目简直...丧心病狂 如果没有强制在线不就是树上莫队入门题? 如果加了强制在线怎么做? 考虑 ...

  8. 【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

    [BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lasta ...

  9. 【SPOJ】QTREE7(Link-Cut Tree)

    [SPOJ]QTREE7(Link-Cut Tree) 题面 洛谷 Vjudge 题解 和QTREE6的本质是一样的:维护同色联通块 那么,QTREE6同理,对于两种颜色分别维护一棵\(LCT\) 每 ...

随机推荐

  1. laravel 5 优化

    性能一直是 Laravel 框架为人诟病的一个点,所以调优 Laravel 程序算是一个必学的技能. 接下来分享一些开发的最佳实践,还有调优技巧,大家有别的建议也欢迎留言讨论. 这里是简单的列表: 配 ...

  2. poj1236 SCC+缩点

    /* 强连通分量内的点可以互相传送,可以直接缩点 缩点后得到一棵树 第一问的答案是零入度点数量, 第二问: 加多少边后变成强连通图 树上入度为0的点有p个,出度为0的点为q,那么答案就是max(p,q ...

  3. Windows安装MongoDB

    一.简介 MongoDB 是一个基于分布式 文件存储的NoSQL数据库 由C++语言编写,运行稳定,性能高 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案 查看官方网站 MongoDB特点 模 ...

  4. JMeter 提供了六种定时器

    JMeter提供了六种定时器,下面让我们一起来学习下JMeter的定时器. 先明确一些概念: 1)定时器是在每个sampler(采样器)之前执行的,而不是之后: 是的,你没有看错,不管这个定时器的位置 ...

  5. ffmpeg切割视频

    using System.Diagnostics; public static void carveVideo() { var inputpath = @"d:\1.mp4"; v ...

  6. MySQL表按月切割

    按月份切割MySQL表数据: 千万级别的数据量也可在毫秒内完成切割操作 注:数据无价请提前自行备份 #!/bin/bash USERNAME=MySQL_user PASSWORD=MySQL_pwd ...

  7. cmake方式使用vlfeat

    目录 environment statement compile vlfeat with cmake compile example project with cmake 1. make sure c ...

  8. Nginx限制下载速度

    http {   limit_conn_zone $binary_remote_addr zone=one:10m; #容器共使用10M的内存来对于IP传输开销 server {        lis ...

  9. javascript 语句和严格模式(三)

    一.语句 javascript程序由语句组成,语句遵守特定的语法规则. block break continue empty if...else switch try catch var functi ...

  10. day6.python字典练习题

    1.有如下变量(tu是个元组),请实现要求的功能 tu = (“alex”, [11, 22, {“k1”: ‘v1’, “k2”: [“age”, “name”], “k3”: (11,22,33) ...