求调昨晚 CF 的 E
  • 板块学术版
  • 楼主2018ljw一般路过HL人
  • 当前回复21
  • 已保存回复21
  • 发布时间2022/7/22 08:43
  • 上次更新2023/10/27 18:59:06
查看原帖
求调昨晚 CF 的 E
128606
2018ljw一般路过HL人楼主2022/7/22 08:43

写的 dsu+trie,现在状态是 TLE on #40,不知道哪里还能优化了/kel

#pragma GCC optimize("Ofast")
#include<cstdio>
int hed[300001],net[600001],ver[600001],tot;
void add(int x,int y){
	ver[++tot]=y;
	net[tot]=hed[x];
	hed[x]=tot;
}
int trie[18000001][2],cnt,root[300001],n;
int sz[300001],a[300001],dis[300001];
int son[300001],se[18000001];
//se 记录的是 trie 树中的 size,sz 与 son 是原树 dsu 用的重儿子。
bool ndc[300001];
// 点 x 是否要被修理
void insert(int id,int val){
	if(!root[id])root[id]=++cnt;
	int pos=root[id],i;
	for(i=29;i>=0;i--){
		se[pos]++;
		int x=((val&(1<<i))!=0);
		if(!trie[pos][x])trie[pos][x]=++cnt;
		pos=trie[pos][x];
	}
	se[pos]++;
}
bool fxor(int id,int val){
	//寻找有无 xor 值相同的
	int pos=root[id],i;
	for(i=29;i>=0;i--){
		int x=((val&(1<<i))!=0);
		if(!trie[pos][x])return 0;
		pos=trie[pos][x];
	}
	return 1;
}
int qval(int id,int rk){
	//查询第 k 大,没有返回 -1
	//唯一作用是 dsu 的时候获取被暴力合并的子树的有用权值
	int pos=root[id],i,val=0;
	if(rk>se[pos])return -1;
	for(i=29;i>=0;i--){
		if(se[trie[pos][0]]>=rk)pos=trie[pos][0];
		else rk-=se[trie[pos][0]],pos=trie[pos][1],val+=1<<i;
	}
	return val;
}
void dfs0(int x,int fr){
	//剖出重儿子并处理出 dis
	int i;
	sz[x]=1;
	dis[x]^=a[x];
	for(i=hed[x];i;i=net[i]){
		int y=ver[i];
		if(y==fr)continue;
		dis[y]=dis[x];
		dfs0(y,x);
		sz[x]+=sz[y];
		if(sz[y]>sz[son[x]])son[x]=y;
	}
}
void dfs1(int x,int fr){
	//找答案
	int i,j;
	if(!son[x]){
		insert(x,dis[x]);
		return;
	}
	dfs1(son[x],x);
	if(!ndc[son[x]])root[x]=root[son[x]];
	//如果重儿子需要修改就不用管,否则直接继承
	for(i=hed[x];i;i=net[i]){
		int y=ver[i];
		if(y==fr||y==son[x])continue;
		dfs1(y,x);
		if(ndc[y]||ndc[x])continue;
		for(j=1;j<=n;j++){
			int val=qval(y,j);
			//提取出合并上去的树的每个权值更新答案。
			if(val==-1)break;
			if(fxor(x,val^a[x])){
				ndc[x]=1;
				break;
			}
		}
		if(ndc[x])continue;
		for(j=1;j<=n;j++){
			int val=qval(y,j);
			if(val==-1)break;
			insert(x,val);
		}
		//把子树的值插进来
	}
	if(fxor(x,dis[x]^a[x]))ndc[x]=1;
	else insert(x,dis[x]);
}
int main(){
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	for(i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs0(1,1);
	dfs1(1,1);
	int res=0;
	for(i=1;i<=n;i++)res+=ndc[i];
	printf("%d",res);
}
2022/7/22 08:43
加载中...