题解 [联合省选 2020 A] 树(LOJ #3303 / 洛谷 P6623)【01-Trie 启发式合并】

题目链接:洛谷 P6623 / LOJ #3303

题意

给定一棵有根树,节点有点权 v ( i ) v(i) v(i)。定义 v a l ( i ) = ⨁ j ( v ( c j ) + d ( c j , x ) ) val(i)=\bigoplus\limits_{j}(v(c_j)+d(c_j,x)) val(i)=j(v(cj)+d(cj,x)),其中 d ( x , y ) d(x,y) d(x,y) x x x y y y 简单路径上边的数量, c j c_j cj i i i 的子树中。求所有节点的 v a l val val 之和。 n , v ( i ) ≤ 525010 n,v(i)\leq 525010 n,v(i)525010

题解

考虑用 01-Trie 来维护所有 v ( c j ) + d ( c j , x ) v(c_j)+d(c_j,x) v(cj)+d(cj,x),并启发式合并。01-Trie 需要支持:

  • 插入一个数;
  • 求全局异或和;
  • 全局加一。

前两个操作容易维护(全局异或和需要每个节点记录其子树里所有数在一些位的异或和);为了支持第三个操作,我们把数按从低位到高位放进 01-Trie,每次交换左右儿子,然后递归处理左(交换前是右)儿子,然后更新自己这个节点维护的异或和。

代码:

/**********
Author: WLBKR5
Problem: loj 3303, luogu 6623 
Name: Ê÷ 
Source: ÁªºÏÊ¡Ñ¡ 2020 A¾í 
Algorithm: 01-Trie, Æô·¢Ê½ºÏ²¢ 
Date: 2020/06/24
Statue: accepted
Submission: loj.ac/submission/844684, www.luogu.com.cn/record/34625636
**********/
#include
using namespace std;
int getint(){
	int ans=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	} 
	while(c>='0'&&c<='9'){
		ans=ans*10+c-'0';
		c=getchar();
	}
	return ans*f;
}
const int N=5.5e5+10,L=21;
struct bian{
	int e,n;
};
bian b[N];
int s[N],tot=0;
void add(int x,int y){
	tot++;
	b[tot].e=y;
	b[tot].n=s[x];
	s[x]=tot;
}

int sz[N*L*2],ch[N*L*2][2],sum[N*L*2],cnt=N;
inline void insert(int x,int val){
	for(int i=0;i<L;i++){
		int t=(val>>i)&1;
		sz[x]++;sum[x]^=(((1<<L-i)-1)<<i)&val; 
		if(!ch[x][t])ch[x][t]=++cnt;
		x=ch[x][t];
	}
	sz[x]++;
}
void add1(int x,int dep=0){
	if(!x)return;
	if(dep==L)return;
	swap(ch[x][0],ch[x][1]);
	add1(ch[x][0],dep+1);
	sum[x]=sum[ch[x][0]]^sum[ch[x][1]];
	sum[x]|=(1<<dep);
	if(!(sz[ch[x][1]]&1))sum[x]^=(1<<dep);
}
int tmp[N],tmpp=0;
void each(int x,int dep,int val){
	if(dep==L){
		for(int i=0;i<sz[x];i++)tmp[tmpp++]=val;
		return;
	}
	if(ch[x][0])each(ch[x][0],dep+1,val);
	if(ch[x][1])each(ch[x][1],dep+1,val|(1<<dep));
}

int val[N];
int szz[N],maxson[N];
void ss1(int x){
	szz[x]=1;
	for(int i=s[x];i;i=b[i].n){
		ss1(b[i].e);
		szz[x]+=szz[b[i].e];
		if(szz[b[i].e]>szz[maxson[x]])maxson[x]=b[i].e;
	}
}
int rt[N];
long long ans=0;
void ss2(int x){
	if(maxson[x]){
		ss2(maxson[x]);
		rt[x]=rt[maxson[x]];
		add1(rt[x]);
		for(int i=s[x];i;i=b[i].n){
			if(b[i].e==maxson[x])continue;
			ss2(b[i].e);
			tmpp=0;each(rt[b[i].e],0,0);
			for(int j=0;j<tmpp;j++)insert(rt[x],tmp[j]+1);
		}
	}else{
		rt[x]=x;
	}
	insert(rt[x],val[x]);
//tmpp=0;each(rt[x],0,0);cerr< ";for(int i=0;i
	ans+=sum[rt[x]];
}

int main(){
	int n=getint();
	for(int i=1;i<=n;i++)val[i]=getint();
	for(int i=2;i<=n;i++)add(getint(),i);
	ss1(1);
	ss2(1);
	cout<<ans;
	return 0;
}

你可能感兴趣的:(题解,#,来源-各省省选,#,数据结构-01-Trie)