CF1055F. Tree and XOR(01字典序&贪心)

CF1055F. Tree and XOR(01字典序&贪心)

思路:01字典序 + + 贪心。

感觉这题挺妙的,因为空间的限制不可能开 1 e 6 × 60 × 2 1e6\times 60\times 2 的数组,所以考虑用两个数组表示当前层和上一层,每次用上一层统计一下该位 0 0 的可能情况,若小于 K K ,说明该位答案只能为 1 1 ,则所有的数都要走相反路径(就是代码中的 p r e pre 更新),另外需要注意的是统计个数时,要用 p r e pre 的儿子统计,因为之前的路径可能发生变化。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
int n,cnt,son[N][2],pre[N],now[N],sz[N],f;
ll ans,sum,k,w[N];
void init(){
	for(int i=1;i<=cnt;i++)
		son[i][0]=son[i][1]=sz[i]=0;
	cnt=sum=f=0;
}
int fun(int x,int y){
	if(!son[x][y]) son[x][y]=++cnt;
	return son[x][y];
}
int main(){
	scanf("%d%lld",&n,&k);pre[1]=now[1]=1;
	for(int i=2,fa;i<=n;i++)
	scanf("%d%lld",&fa,&w[i]),w[i]^=w[fa],pre[i]=now[i]=1;
	for(int i=61;~i;i--){
		init();
		for(int j=1;j<=n;j++)
			now[j]=fun(now[j],w[j]>>i&1),sz[now[j]]++; 
		for(int j=1;j<=n;j++)	sum+=sz[son[pre[j]][w[j]>>i&1]];//这里只能用pre得到,因为上一层的pre可能发生了变化. 
		if(sum<k) k-=sum,ans+=1LL<<i,f=1;							//即因为贪心走向了另一条路. 
		for(int j=1;j<=n;j++)
			pre[j]=son[pre[j]][(w[j]>>i&1)^f];
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/107598278