NC20006. [HEOI2013]EDEN的博弈问题
描述
输入描述
每个测试点包含一组测试数据。
测试数据的第一行包含一个正整数n,表示博弈树的节点数目。
节点从1到n 编号,且 1 号节点为根节点。
之后n–1 行,每行包含一个正整数。第i行的正整数表示节点i的父节点的编号。
输出描述
在一行内输出三个空格分隔的正整数,分别是编号最小的关键叶节点的编号, 关键叶节点的数目和所有关键叶节点的编号的异或和。
示例1
输入:
7 1 1 2 2 3 3
输出:
4 4 0
C++11(clang++ 3.9) 解法, 执行用时: 42ms, 内存消耗: 8428K, 提交时间: 2020-03-28 23:26:20
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int N=200005; const int inf=1000000000; int n,dep[N],cnt,last[N],f[N],tag[N]; struct edge { int to,next; }e[N]; void addedge(int u,int v) { e[++cnt].to=v; e[cnt].next=last[u]; last[u]=cnt; } void dp1(int x,int fa) { dep[x]=dep[fa]+1; for(int i=last[x];i;i=e[i].next) dp1(e[i].to,x); if(!last[x]) { f[x]=1; return; } if(dep[x]&1) { f[x]=inf; for(int i=last[x];i;i=e[i].next) if(f[x]=min(f[x],f[e[i].to])); } else { f[x]=0; for(int i=last[x];i;i=e[i].next) f[x]+=f[e[i].to]; } } void work1(int x) { if(!last[x]) tag[x]++; if(dep[x]&1) { for(int i=last[x];i;i=e[i].next) if(f[e[i].to]==f[x]) work1(e[i].to); } else { for(int i=last[x];i;i=e[i].next) work1(e[i].to); } } void dp2(int x) { for(int i=last[x];i;i=e[i].next) dp2(e[i].to); if(!last[x]) { f[x]=1; return; } if(dep[x]&1) { f[x]=0; for(int i=last[x];i;i=e[i].next) f[x]+=f[e[i].to]; } else { f[x]=inf; for(int i=last[x];i;i=e[i].next) if(f[x]=min(f[x],f[e[i].to])); } } void work2(int x) { if(!last[x]) tag[x]++; if(dep[x]&1) { for(int i=last[x];i;i=e[i].next) work2(e[i].to); } else { for(int i=last[x];i;i=e[i].next) if(f[e[i].to]==f[x]) work2(e[i].to); } } int main() { scanf("%d",&n); for(int i=2,x;i<=n;i++) scanf("%d",&x),addedge(x,i); dp1(1,0); work1(1); dp2(1); work2(1); int s1=0,s2=0; for(int i=1;i<=n;i++) if(tag[i]==2) { printf("%d ",i); break; } for(int i=1;i<=n;i++) if(tag[i]==2) s1++,s2^=i; printf("%d %d",s1,s2); return 0; }