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;
}

浙公网安备 33010602011771号