[Question Solution] LuoGu6623: [The Provincial Election Joint Examination 2020 A Volume] Tree

The original question portal.
Consider the contribution of the number at a point to the whole.
Because it is or, consider the contribution of each digit of a certain number to the whole.
Add the number at a point to 3, add this 3 and its ancestors Write the contribution form. The
number of digits from right to left is 0123...
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111.
Take out the first binary number separately, and find that it is Regular: 1001100110011……The
first place, 01 has a loop length of 2 2 2^222. In each loop section, 0/1 repeats2 1 2^12Once , for the2 1 2^1whose digit value is 1.21 number I can producexor 2 1 xor2^1xor21 contributed
by extension
k-th bit, the cycle length of the section 01 is2 k + 1 2 ^ {k2k + 1 , in each cycle section, 0/1 repeats2 k 2^k2k times, for the2 k 2^kwhose digit value is 1.2k number I can producexor 2 k xor2 ^ kxor2The contribution of k
can be differentiated on the tree. For each bit, the first1 1 ineach cyclic node1 position or above2 k 2^k2k , the first0 0The position of 0 is also2 k 2^k2k , which means a segment value is1 1The interval of 1 can also be up to2 k 2^k2k
Then continue to optimize the difference, and find the subscriptiiof the difference array to be changedi , for thekkk bits, always satisfyi mod 2 k = 0 i\text{ mod }2^k=0i  mod  2k=0 i  and  ( 2 k − 1 ) = 0 i\text{ and }(2^k-1)=0 i and (2k1)=0
For a point, to find out which ancestors of one's own can be also or, you can use depth to describe
if one's own weightau a_uain, Plus the depth difference between the ancestor and himself deltad delta_ddeltad, 即au + delta a_u + delta_dain+deltadIs the ii mentioned abovei , but indfs dfsIn the process of d f s , you can only get “related to yourself” each time, which is transformed intoau + du and dv for 2 k congruence a_u+d_u and d_v for 2^k congruenceain+dinWith dvFor to 2k withmore thanwherevvv ShiuuThe ancestor of u , the
difference on the subtree isO (nlogn) O(nlogn)O ( n l o g n )

Code:

#include <bits/stdc++.h>
#define maxn 1000010
#define maxm 25
using namespace std;
long long ans;
struct Edge{
    
    
	int to, next;
}edge[maxn];
int num, head[maxn], a[maxn], val[25][maxn], n, power[25];

inline int read(){
    
    
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

void addedge(int x, int y){
    
     edge[++num] = (Edge){
    
    y, head[x]}, head[x] = num; }

int dfs(int u, int d){
    
    
	int s = a[u];
	for (int i = 0; i <= 20; ++i) val[i][(d + a[u]) & (power[i] - 1)] ^= power[i];
	for (int i = 0; i <= 20; ++i) s ^= val[i][d & (power[i] - 1)];
	for (int i = head[u]; i; i = edge[i].next) s ^= dfs(edge[i].to, d + 1);
	for (int i = 0; i <= 20; ++i) s ^= val[i][d & (power[i] - 1)];
	ans += s;
	return s;
}

int main(){
    
    
	n = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	for (int i = 2; i <= n; ++i) addedge(read(), i);
	power[0] = 1;
	for (int i = 1; i <= 20; ++i) power[i] = power[i - 1] << 1;
	dfs(1, 0);
	printf("%lld\n", ans);
	return 0;
}

Guess you like

Origin blog.csdn.net/ModestCoder_/article/details/108477015