【题解】洛谷 P4096 [HEOI2013] Eden 的博弈树 | 更简洁的一种做法

洛谷 P4096 [HEOI2013] Eden 的博弈树,一种由 xzm 大神提供的更简洁做法。

首先需要从下往上求出以 \(i\) 为根的子树先后手的最小必胜集合大小,记为 \(f_{i,0/1}\)\(0\) 为先手,\(1\) 为后手)。此外在转移同时维护该子树内的三个问题的答案。

对于先手而言,只要取一个儿子能必胜就能获胜,显然就是取所有儿子中的后手最小必胜集合大小最小的,\(f_{i,0}=\min f_{son,1}\)

对于后手而言,需要取使所有儿子先手都能必胜才能获胜,\(f_{i,1}=\sum f_{son,0}\)

注意到子树内先手最小必胜集合一定是后手最小必胜集合的子集,故关键节点集合即两者交集就是先手必胜集合,子树内答案就是将所有能贡献到先手的子结点(满足 \(f_{j\in son,1}=f_{i,0}\) 的儿子 \(j\))的答案合并(\(a_i=\min a_j,b_i=\sum b_j,c_i=\bigoplus c_j\))。

输出根节点答案即可。嗯对,做完了。

#include <bits/stdc++.h>
#define mem(a,v) memset(a,v,sizeof(a))
#define endl '\n'
#define FILE(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout);
#define pii pair<int,int>
#define pll pair<long long,long long>
#define st first
#define nd second
#define pb push_back
using namespace std;
using ll=long long;
using lld=long double;
const int N=2e5+10;
int n,fa[N],f[N][2],a[N],b[N],c[N];
vector<int>g[N];
void dfs(int u){
    if(!g[u].size()){
        f[u][1]=f[u][0]=1,
        a[u]=u,b[u]=1,c[u]=u;
        return;
    }
    f[u][0]=INT_MAX;
    for(int v:g[u]){
        dfs(v);
        if(f[v][1]<f[u][0])
            f[u][0]=f[v][1],a[u]=a[v],b[u]=b[v],c[u]=c[v];
        else if(f[v][1]==f[u][0])
            a[u]=min(a[v],a[u]),b[u]+=b[v],c[u]^=c[v];
        f[u][1]+=f[v][0];
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    // FILE("game");
    cin>>n;
    for(int i=2;i<=n;i++)
        cin>>fa[i],g[fa[i]].pb(i);
    dfs(1);
    cout<<a[1]<<' '<<b[1]<<' '<<c[1];
    return 0;
}
posted @ 2025-10-22 17:27  青铜_WU  阅读(3)  评论(0)    收藏  举报