P6623 省选联考 2020 A 卷 树 Sol

题目链接

考虑对于每一位进行考虑。

先考虑对于一个数 \(x\),什么时候其对于第 \(k\) 位的贡献会改变。显然的,只有 \(x \equiv 2^k-1 \pmod{2^k}\) 时,会出现这种情况。

因此我们假设目前对于第 \(k\) 位进行考虑。令 \(val_i = c_i + dis(1,i)\),则在什么时候节点 \(v\) 的贡献会对节点 \(u\) 发生改变?仔细考虑一下,发现是 \(c_v + dis(u,v) - 1 \equiv 2^k-1 \pmod{2^k}\),使用 \(val\) 进行代换,就变成了 \(val_v \equiv dis(1,u) \pmod{2^k}\)

因此我们就可以针对某一位,对着 \(val\) 进行记录了,使用桶和启发式合并可以解决。

时间复杂度 \(O(n \log^2 n)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 525010 + 10;
int ans[N];
vector<int> G[N];
int L[N],R[N],dfn[N],idfn[N],tot;
int n;
int d[N],val[N],c[N];
int siz[N],son[N];
int cnt[N << 1][22];
void dfs(int u){
	dfn[u] = ++tot;idfn[tot] = u;
	L[u] = tot;
	siz[u] = 1;
	for(int v : G[u]){
		d[v] = d[u] + 1;
		dfs(v);
		siz[u] += siz[v];
		if(siz[son[u]] < siz[v])
			son[u] = v;
	}
	R[u] = tot;
	return ;
}
void update(int num,int k){
	for(int i=0;i<=21;i++)
		cnt[num % (1 << i)][i] += k;
	return ;
}
void get_ans(int u){
	for(int v : G[u])
		ans[u] ^= ans[v];
	for(int i=0;i<=21;i++)
		if(cnt[d[u] % (1 << i)][i] & 1)
			ans[u] ^= (1 << i);
	return ;
}
void solve(int u){
	for(int v : G[u]){
		if(v == son[u]) continue;
		solve(v);
		for(int i=L[v];i<=R[v];i++)
			update(val[idfn[i]],-1);
	}
	if(son[u])
		solve(son[u]);
	for(int v : G[u]){
		if(v == son[u]) continue;
		for(int i=L[v];i<=R[v];i++)
			update(val[idfn[i]],1);
	}
	get_ans(u);
	ans[u] ^= c[u];
	update(val[u],1);
}
int main(){
	IOS;
	cin >> n;
	for(int i=1;i<=n;i++)
		cin >> c[i];
	for(int i=2;i<=n;i++){
		int x;
		cin >> x;
		G[x].push_back(i);
	}
	d[1] = 1;
	dfs(1);
	for(int i=1;i<=n;i++)
		val[i] = d[i] + c[i];
	solve(1);
	LL sum = 0;
	for(int i=1;i<=n;i++)
		sum += 1ll * ans[i];
	cout << sum;
	return 0;
}
posted @ 2026-05-14 16:14  WinterXorSnow  阅读(12)  评论(0)    收藏  举报