Luogu P6623 [省选联考 2020 A 卷] 树

这套路和AGC044C几乎一样,做过那题的就跟做原题一样

显然考虑用0/1Trie维护答案,考虑从子树向这个点合并,显然我们的操作有:

加入一个数,Trie树合并,Trie树集体加\(1\),前两个非常直观,考虑最后一个操作

我们把Trie树反着建,从低位到高位建树,这样每次加\(1\)操作其实就是交换\(0,1\)儿子之后递归处理\(0\)儿子

统计出每个点\(0,1\)儿子的个数以及以它为根的Trie树中不同深度的\(0,1\)儿子个数之和,可以轻松维护答案

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int P=21,N=1<<P;
struct edge
{
	int to,nxt;
}e[N]; int n,head[N],v[N],x,cnt; long long ans;
inline void addedge(CI x,CI y)
{
	e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
}
class Trie
{
	private:
		struct segment
		{
			int ch[2],c[2];
		}node[N*P]; int rt[N],cq[N][P][2],tot;
		#define lc(x) node[x].ch[0]
		#define rc(x) node[x].ch[1]
		#define C(x,y) node[x].c[y]
		inline void _insert(int& now,CI val,CI id,CI dep=0)
		{
			if (dep==P) return; if (!now) now=++tot;
			if ((val>>dep)&1) _insert(rc(now),val,id,dep+1),++C(now,1),++cq[id][dep][1];
			else _insert(lc(now),val,id,dep+1),++C(now,0),++cq[id][dep][0];
		}
		inline void _add(CI now,CI id,CI dep=0)
		{
			if (!now||dep==P) return; RI i; for (i=0;i<2;++i) cq[id][dep][i]-=C(now,i);
			swap(lc(now),rc(now)); swap(C(now,0),C(now,1));
			for (i=0;i<2;++i) cq[id][dep][i]+=C(now,i); _add(lc(now),id,dep+1);
		}
		inline int _merge(CI x,CI y,CI dep=0)
		{
			if (!x||!y||dep==P) return x|y; for (RI i=0;i<2;++i) C(x,i)+=C(y,i);
			lc(x)=_merge(lc(x),lc(y),dep+1); rc(x)=_merge(rc(x),rc(y),dep+1); return x;
		}
	public:
		inline void insert(CI pos,CI mv)
		{
			_insert(rt[pos],mv,pos);
		}
		inline void add(CI pos)
		{
			_add(rt[pos],pos);
		}
		inline void merge(CI x,CI y)
		{
			rt[x]=_merge(rt[x],rt[y]); for (RI i=0,j;i<P;++i)
			for (j=0;j<2;++j) cq[x][i][j]+=cq[y][i][j];
		}
		inline int query(CI pos,int ret=0)
		{
			for (RI i=0;i<P;++i) if (cq[pos][i][1]&1) ret|=(1<<i); return ret;
		}
		#undef lc
		#undef rc
		#undef V
}T;
#define to e[i].to
inline void DFS(CI now=1)
{
	T.insert(now,v[now]); for (RI i=head[now];i;i=e[i].nxt)
	DFS(to),T.add(to),T.merge(now,to); ans+=T.query(now);
}
#undef to
int main()
{
	RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&v[i]);
	for (i=2;i<=n;++i) scanf("%d",&x),addedge(x,i);
	return DFS(),printf("%lld",ans),0;
}
posted @ 2020-07-28 16:32  空気力学の詩  阅读(147)  评论(0编辑  收藏  举报