正题
题目链接:https://www.luogu.com.cn/problem/P4096
题目大意
一个博弈树,黑方先手。定义一个最小的叶子节点集为黑胜状态为黑方胜利集合,白色亦然。求所有既属于黑方胜利集合有属于白方胜利集合的点。
解题思路
设fi,0/1f_{i,0/1}fi,0/1表示iii子树中的最小黑发/白方胜利集和,然后可以根据这个求出所有的胜利集合点。
时间复杂度O(n)O(n)O(n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct node{int to,next;
}a[N];
int n,tot,ls[N],f[N][2];
bool con[N][2];
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
void dfs(int x,int j,int k){if(!ls[x]){f[x][k]=1;return;}if(j!=k)f[x][k]=2147483647;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;dfs(y,j^1,k);if(j!=k)f[x][k]=min(f[x][k],f[y][k]);else f[x][k]+=f[y][k];}return;
}
void solve(int x,int j,int k){if(!ls[x])con[x][k]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(j!=k&&f[y][k]!=f[x][k])continue;solve(y,j^1,k);}return;
}
int main()
{scanf("%d",&n);for(int i=2;i<=n;i++){int x;scanf("%d",&x);addl(x,i);}dfs(1,0,0);dfs(1,0,1);solve(1,0,0);solve(1,0,1);int ans1=2147483647,ans2=0,ans3=0;for(int i=1;i<=n;i++)if(con[i][1]&&con[i][0])ans1=(ans1<2147483647)?ans1:i,ans2++,ans3^=i;printf("%d %d %d\n",ans1,ans2,ans3);
}