Gym102832F.Strange Memory(树上启发式合并+STL)

给出一棵树。

当两个点的点权异或和等于它们LCA的点权的时候,它们的下标异或和会被统计到答案里。

询问答案。

对同一个点,它不同子树内的点点权异或和等于这个点的点权的时候,可以作为答案。

那么就先对最大的那颗子树维护一个map,剩下的点往最大的这颗子树上合并

这个点的map可以继续往上合并

map<int,vector > mp;表示值为x的下标

#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);
}
posted @ 2021-03-29 20:09  zlc0405  阅读(72)  评论(0编辑  收藏  举报