蓝的写。先放个带注释代码凑数。
```cpp
#include <bits/stdc++.h>
using namespace std;
namespace obasic{typedef long long lolo;typedef vector<int> vecint;template <typename _T>void readi(_T &x){_T k=1;x=0;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';x*=k;return;}template <typename _T>void writi(_T x){if(x<0)putchar('-'),x=-x;if(x>9)writi(x/10);putchar(x%10+'0');}
};
using namespace obasic;
const int MaxN=5.3e5,MaxNb=21;
int N,A[MaxN],X,W[MaxNb][MaxN];
vector<int> Tr[MaxN];lolo fans;
void addedge(int u,int v){Tr[u].push_back(v);}
lolo dfs(int u,int d){int cans=A[u];for(int i=0;i<MaxNb;i++)W[i][(d+A[u])&((1<<i)-1)]^=(1<<i);//我们来思考一下,首先我们知道当我们按位考虑//第k位会给自己的U[b2^(k+1)+a,b2^(k+1)+a+2^k)级祖先打一个加1的贡献。//要给这么多区间打贡献,不如直接打差分。然而这样仍然是O(N^2)的。//观察到所有要打上差分的下标模2^k相等,所以把它们丢在一个桶里面自取。//问题来了,这个a等价于什么?代码里面又要怎么写?//(上文a并不实际出现在代码中)//推理一下,深度为d的u,其末k位为A[u]的;//深度为d-1的u,其末那些位就是为A[u]+1的。//(感性理解,模意义下)深度为d+A[u]的u,其末那些位就是为0的。//相应地深度为d+A[u]+2^k的u开始其末那些位就是为1的。//那差分数组就刚好打在所有模2^k余((d+A[u])%(2^k))的地方了//很巧妙的树上开桶差分算贡献,可以和LGP1600相媲美//建议对照学习,更深刻地体会树上差分思想。for(int i=0;i<MaxNb;i++)cans^=W[i][d&((1<<i)-1)];for(int v : Tr[u])cans^=dfs(v,d+1);for(int i=0;i<MaxNb;i++)cans^=W[i][d&((1<<i)-1)];//进dfs异或一道,出dfs再异或一道//可以理解为先xor a再xor (a xor b)//等效于xor b,b即子树内做出来的贡献//这归功于异或有自反性。fans+=cans;return cans;
}
int main(){readi(N);for(int i=1;i<=N;i++)readi(A[i]);for(int i=2;i<=N;i++)readi(X),addedge(X,i);dfs(1,0);writi(fans);return 0;
}