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

考试前几天刚刚考了01trie整体加一这个trick,但是我当时口胡没写。考场上乱写写了一年没写对。。。

这个题的做法就是对每个点维护一个01trie,然后每次向上合并就啥也没有了。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N=580000;
int rt[N],n,p[N],head[N],cnt,pool;
long long ans;
struct Trie
{
	#define MaxN 20
	int w[N*MaxN],ch[N*MaxN][2],xorv[N*MaxN],Cnt;
	
	void push_up(int k)
	{
		w[k]=xorv[k]=0;
		if(ch[k][0])
			w[k]^=w[ch[k][0]],
			xorv[k]^=xorv[ch[k][0]]<<1;
		if(ch[k][1])
			w[k]^=w[ch[k][1]],
			xorv[k]^=(xorv[ch[k][1]]<<1)|w[ch[k][1]];
	}
	
	int New() {return ++pool; }
	
	void Insert(int &k,int x,int dep)
	{
		if(!k) k=New();
		if(dep>MaxN) { w[k]^=1;return; }
		Insert(ch[k][x&1],x>>1,dep+1);
		push_up(k);
	}
	
	void addall(int k)
	{
		swap(ch[k][0],ch[k][1]);
		if(ch[k][0]) addall(ch[k][0]);
		push_up(k);
	}
	
	int merge(int a,int b)
	{
		if(!a||!b) return a+b;
		w[a]^=w[b],xorv[a]^=xorv[b];
		ch[a][0]=merge(ch[a][0],ch[b][0]);
		ch[a][1]=merge(ch[a][1],ch[b][1]);
		return a;
	}
}T;
struct Edge
{
	int nxt,to;
}g[N*2];

int read()
{
	int x=0;
	char c=getchar();
	while(c<'0'||c>'9')
		c=getchar();
	while(c>='0'&&c<='9')
		x=x*10+c-'0',c=getchar();
	return x;
}

void add(int from,int to)
{
	g[++cnt].nxt=head[from];
	g[cnt].to=to;
	head[from]=cnt;
}

void init()
{
	n=read();
	for (int i=1;i<=n;i++)
		p[i]=read();
	for (int x,i=2;i<=n;i++)
		x=read(),
		add(x,i),add(i,x);
}

void dfs(int x,int fa)
{
	T.Insert(rt[x],p[x],0);
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		dfs(v,x);
		T.addall(rt[v]);
		T.merge(rt[x],rt[v]);
	}
	ans+=T.xorv[rt[x]];
}

void work()
{
	dfs(1,-1);
	printf("%lld\n",ans);
}

signed main()
{
	init();
	work();
	return 0;
}
posted @ 2020-07-14 21:30  With_penguin  阅读(110)  评论(0编辑  收藏  举报