P6623 [省选联考 2020 A 卷] 树
P6623 [省选联考 2020 A 卷] 树
题目描述
给定一棵
设
其中
请你求出
输入格式
第一行一个正整数
第二行
接下来一行
输出格式
仅一行一个整数表示答案。
【数据范围】
对于
Solution:
好神的二进制题。
我们发现从祖先子树是不明智的,所以我们考虑刻画单点对于祖先的影响:
K | val |
---|---|
0 | 001001 |
1 | 001010 |
2 | 001011 |
3 | 001100 |
4 | 001101 |
5 | 001110 |
6 | 001111 |
7 | 010000 |
8 | 010001 |
9 | 010010 |
10 | 010011 |
bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
2 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
3 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
打完这张表之后我们发现随着相对深度的上涨,一个点对其
那么一种较为朴素的想法是从当前节点
假设现在我们只考虑
我们考虑利用一下循环节这一特性,我们可以打一个差分,来维护那些点需要异或上1,然后我们就发现,对于一个点
那么如何保证子树内节点只对祖先贡献呢?很简单,我们对
Code:
#include<bits/stdc++.h> #define int long long const int N=6e5+5; const int lg=20; using namespace std; int bit[lg+5],full_bit[lg+5]; int w[lg+5][N],val[N]; vector<int> E[N]; int n,sum; void init() { for(int i=0;i<=lg;i++)bit[i]=(1ll<<i); for(int i=0;i<=lg;i++)full_bit[i]=bit[i]-1; } int dfs(int x,int dep) { int ans=val[x]; for(int j=0;j<=lg;j++)w[j][(dep+val[x])&(full_bit[j])]^=bit[j];//&full_bit :对2^j 取模 for(int j=0;j<=lg;j++)ans^=w[j][dep&(full_bit[j])]; for(auto y : E[x])ans^=dfs(y,dep+1); for(int j=0;j<=lg;j++)ans^=w[j][dep&(full_bit[j])]; sum+=ans; return ans; } void work() { cin>>n; init(); for(int i=1;i<=n;i++)scanf("%lld",&val[i]); for(int u=2,v;u<=n;u++)scanf("%lld",&v),E[v].emplace_back(u); dfs(1,0); cout<<sum; } #undef int int main() { //freopen("P6623.in","r",stdin);freopen("P6623.out","w",stdout); work(); return 0; }