题解:P7864 「EVOI-RD1」摘叶子
考虑是否有能够使胜败局面转换的性质或操作。
-
给 \(G\) 中任意一个非叶子节点加上一个叶子,则新的 \(G'\) 一定是必胜态。
-
证明:
-
如果 \(G\) 为必胜态,则先手按照 \(G\) 的策略操作,同时把新的叶子也摘掉。则剩下的就是必败态。
-
如果 \(G\) 为必败态,先手把新的叶子摘掉。则剩下的就是原来的必败态 \(G\)。得证。
-
-
由上面结论可知,如果一个非叶子节点有至少两个儿子,且有儿子为叶子,则可以看作 \(G\) 是由没有这个叶子的 \(G'\) 加上叶子变来的,则为必胜态。
-
若 \(G\) 不满足第 2 条,则所有叶子节点的父亲都只有一个儿子。
-
若所有的节点都只有一个儿子,也就是说树退化成了链,则容易判断。
-
若存在有多个儿子的节点:
-
在两个人不断摘叶子的过程中,一定会出现第 2 条的局面,这样就可以判出胜负。
-
则我们要判断出现这种局面时,是哪一方先手。
-
对于一个多个儿子的节点 \(u\),如果 \(u\) 子树内还有多个儿子的节点,则 \(u\) 是不用判断的(子树的的一定先达到第 2 条)。
-
我们考察 \(u\) 儿子节点 \(v\) 到达叶子的距离(此时 \(v\) 往下都是链,所以对应叶子是唯一的),也就是 \(v\) 成为叶子的需要在这条链上操作的步数 \(cnt\)。
-
如果 \(cnt\) 为奇数,我们可以发现只要先手使 \(cnt\) 减一,后手就可以跟着把 \(cnt\) 减一。\(cnt\) 奇偶性不变。那么,最后一定是后手可以摘到 \(v\)。
-
如果 \(cnt\) 为偶数,则先手可以用一步操作把它变为奇数。这样就变成了先手跟着后手摘叶子,先手必胜。
-
-
也就是说如果存在 \(cnt\) 为偶数的 \(u\),先手就把它们全都变为奇数,这样无论后手怎么操作都是必败态。相反如果全是奇数,则先手必败。
时间复杂度线性。
#include <bits/stdc++.h>
using namespace std;
#define LG(x) (31^__builtin_clz(x))
#define ll long long
#define SIZIO (1<<22)
#define gc() (rp1==rp2&&(rp2=(rp1=buf)+fread(buf,1,SIZIO,stdin))==rp1?EOF:*rp1++)
char buf[SIZIO+1],*rp1,*rp2;
inline int read(){
int d=0,f=0;char ch=gc();
while (!isdigit(ch)) f|=(ch=='-'),ch=gc();
while (isdigit(ch)) d=(d<<1)+(d<<3)+ch-'0',ch=gc();
return f?-d:d;
}
const int N=1000005;
int n,e[N],ne[N],h[N],idx=1,flag,hg[N],FF,st[N];
// flag 答案 FF 是否有cnt为偶数
inline void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
void dfs(int u){
int son=0,f=0,F=0;
//son 儿子数 f(0/1) 是否有儿子为叶子 F(0/1) 是否有cnt为偶数
hg[u]=st[u]=0;
for (int i=h[u];i;i=ne[i]){
int v=e[i];
dfs(v),son++,st[u]|=st[v];
hg[u]=max(hg[u],hg[v]+1);
if (!hg[v]) f=1;
if (!(hg[v]&1)) F=1;
}
if (st[u]) return ;
if (son>1) {
st[u]=1;
if (f||F) flag=1;
}
}
inline void solve(){
n=read(),idx=1;flag=FF=0;
for (int i=1;i<=n;i++) h[i]=0;
for (int i=2;i<=n;i++) add(read(),i);
dfs(1);
if (hg[1]==n-1) flag|=(n&1);//链
putchar('0'+flag);putchar('\n');
}
int main(){
int T=read();
while (T--) solve();
return 0;
}

浙公网安备 33010602011771号