Gym102832F.Strange Memory(树上启发式合并+STL)
给出一棵树。
当两个点的点权异或和等于它们LCA的点权的时候,它们的下标异或和会被统计到答案里。
询问答案。
对同一个点,它不同子树内的点点权异或和等于这个点的点权的时候,可以作为答案。
那么就先对最大的那颗子树维护一个map,剩下的点往最大的这颗子树上合并
这个点的map可以继续往上合并
map<int,vector
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
vector<int> g[maxn];
int a[maxn],n,size[maxn];
int son[maxn];
long long ans=0;
void dfs1 (int x,int pre) {
size[x]=1;
for (int y:g[x]) {
if (y==pre) continue;
dfs1(y,x);
size[x]+=size[y];
if (size[y]>size[son[x]]) {
son[x]=y;
}
}
}
map<int,vector<int> > dfs2 (int x,int pre) {
if (!son[x]) {
map<int,vector<int> > mp;
mp[a[x]].push_back(x);
return mp;
}
map<int,vector<int> > mp=dfs2(son[x],x);
for (int y:g[x]) {
if (y==pre||y==son[x]) continue;
map<int,vector<int> > mp1=dfs2(y,x);
for (auto it=mp1.begin();it!=mp1.end();it++) {
for (int j:it->second)
for (int k:mp[a[x]^it->first]) {
ans+=j^k;
}
}
for (auto it=mp1.begin();it!=mp1.end();it++) {
for (int j:it->second) mp[it->first].push_back(j);
}
}
mp[a[x]].push_back(x);
return mp;
}
int main () {
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",a+i);
for (int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(1,0);
//for (int i=1;i<=n;i++) printf("%d ",son[i]);
//printf("\n");
map<int,vector<int> > mp=dfs2(1,0);
printf("%lld\n",ans);
}