CF1055F. Tree and XOR(01字典序&贪心)
思路:01字典序 贪心。
感觉这题挺妙的,因为空间的限制不可能开 的数组,所以考虑用两个数组表示当前层和上一层,每次用上一层统计一下该位 的可能情况,若小于 ,说明该位答案只能为 ,则所有的数都要走相反路径(就是代码中的 更新),另外需要注意的是统计个数时,要用 的儿子统计,因为之前的路径可能发生变化。
#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;
}