思路有了,占坑,做完来写
想了很久的题主要纠结的是树上的操作怎么影响先后输赢,后来先发现了叶节点的上一层节点的先后是必抢的(必胜状态),这个节点又是由上一层节点决定,于是想到了奇书层或者偶数层的结点是要满足nim博弈的,想到这边差不多可以做了。
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<stdlib.h>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
int n;
#define maxn 100010
int a[maxn];
vector <ll> g[maxn];
ll num;
ll l[maxn];
int it[maxn];
map <ll,ll> p;
map <ll,ll> q;
ll lmax ( ll a, ll b){
if (a>b)return a;
else return b;
}
void dfs (int v,int level ){
l[v]=level;
int i;
num = lmax (num ,level);
for (i=0;i<g[v].size ();i++){
int u = g[v][i];
if (!u) continue;
dfs (u,level+1);
}
return ;
}
int main (){
int i;
scanf ("%d",&n);
for (i=1;i<=n;i++){
scanf ("%d",&a[i]);
it[i]=a[i];
}
for (i=2;i<=n;i++){
int f;
scanf("%d",&f);
g[f].push_back (i);
}
num = 0;
dfs (1,1);
int pp = num %2;
ll ans =0;
ll oddnum = 0,rnum=0;
sort (a+1,a+1+n);
int len = unique (a+1,a+1+n)-(a+1) ;
for (i=1;i<=n;i++){
if (l[i]%2==pp){
ans ^= it[i];
p[it[i]]++;
}
else q[it[i]]++;
if (l[i]%2==1) {oddnum++;
}
else {rnum ++ ;}
}
if (!ans){
ll temp =ans;
ans = oddnum *(oddnum-1)/2 + rnum*(rnum-1)/2;
for (i=1;i<=len;i++){
ans += p[a[i]]*q[a[i]] ;
}
printf("%lld\n", ans);
}
else {
ll temp = ans;
ans = 0;
for (i=1;i<=n;i++){
if (l[i]%2==pp){
ans += q[temp^it[i]];
}
}
printf("%lld\n", ans);
}
}