2020CCPC长春站
对每个节点,考虑其子树对它的贡献
dsu on tree
先计算轻儿子,后计算重儿子,这样重儿子计算完贡献就不用清空,但是轻儿子要清空
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],n,x,m;
long long ans;
int dfn[N],L[N],R[N],o,u,v,sz[N],son[N];
vector<int>g[N];
int f[N*11][20][2];
//考虑每个节点的贡献,枚举子树
//f[i][j][k]表示权值为i第j为k的个数
void dfs(int u,int fa=0){
sz[u]=1;
dfn[++o]=u;
L[u]=o;
for(auto j:g[u]){
if(j==fa)continue;
dfs(j,u);
sz[u]+=sz[j];
if(sz[j]>sz[son[u]])son[u]=j;
}
R[u]=o;
}
void dsu(int u,int fa=0,int op=1){
for(auto j:g[u]){
if(j==fa||j==son[u])continue;
dsu(j,u,1);
}
if(son[u])dsu(son[u],u,0);
for(int i=0;i<20;i++)f[a[u]][i][u>>i&1]++;
for(auto j:g[u]){
if(j==fa||j==son[u])continue;
for(int k=L[j];k<=R[j];k++){
for(int i=0;i<20;i++){
int p=a[u]^a[dfn[k]];
int c=dfn[k]>>i&1;
ans+=(1ll<<i)*f[p][i][1-c];
}
}
for(int k=L[j];k<=R[j];k++){
for(int i=0;i<20;i++)f[a[dfn[k]]][i][dfn[k]>>i&1]++;
}
}
if(op){
for(int j=L[u];j<=R[u];j++){
int p=dfn[j];
for(int i=0;i<20;i++)f[a[p]][i][p>>i&1]--;
}
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n;i++){
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1);
dsu(1);
cout<<ans;
}
https://zhuanlan.zhihu.com/p/578936645
https://zhuanlan.zhihu.com/p/537511158