P9745 「KDOI-06-S」树上异或

发布时间 2023-11-17 13:00:54作者: wscqwq

P9745 「KDOI-06-S」树上异或

参考:https://www.luogu.com.cn/blog/710100/p9745-kdoi-06-s-shu-shang-yi-huo-jian-yao-ti-xie

其中,转移中一部分考虑的是断边,那么两部分分离,乘法原理;如果连边,需要异或为0,就00或11,为1,就01或10.按位分离计算,最后的f就是综合起来。

#include<iostream>
#include<cstring>
using namespace std;
const int mod=998244353,N=500010,P=60;
typedef long long ll;
ll a[N];
int f[N],p2[N],g[N][P][2],n,h[N],e[N],ne[N],idx;//don't forget memset h!
void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x){
	for(int i=h[x];~i;i=ne[i]){
		int j=e[i];
		dfs(j);
		for(int k=0;k<P;++k){
			int x0=g[x][k][0],x1=g[x][k][1];
			int j0=g[j][k][0],j1=g[j][k][1];
			g[x][k][0]=(1ll*x0*f[j]%mod+1ll*x0*j0%mod+1ll*x1*j1%mod)%mod;
			g[x][k][1]=(1ll*x1*f[j]%mod+1ll*x0*j1%mod+1ll*x1*j0%mod)%mod;
		}
	}
	for(int k=0;k<P;++k)f[x]=(f[x]+1ll*p2[k]*g[x][k][1]%mod)%mod;
}

int main() {
	ios::sync_with_stdio(false); 
	cin.tie(0),cout.tie(0);
	cin>>n;
	p2[0]=1;
	for(int i=1;i<P;++i)p2[i]=(p2[i-1]<<1)%mod;
	memset(h,-1,n*4+4);
	for(int i=1;i<=n;i++){
		cin>>a[i];
		for(int k=0;k<P;++k)g[i][k][a[i]>>k&1]=1;
	}
	for(int i=2;i<=n;i++){
		int x;
		cin>>x;
		add(x,i);
	}
	dfs(1);
	cout<<f[1]<<'\n';
}