题目链接:[KSN2021] Binary Land
我们可以发现,如果一个数字最高位之后有一个0,那么是可以连向某个对应位置最高位为1的数字。
然后这个不难想到可以对每一个二进制位建立虚点。
我们发现如果这个虚点有作用,那么一定是某个数字最高位是这个,并且某个数字最高位之后某个0是这个。然后并查集维护连通性即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int n,a[N],b[N],f[N],vis[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void merge(int x,int y){
x=find(x),y=find(y);
if(x!=y) f[x]=y,b[y]+=b[x];
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<N;i++) f[i]=i;
for(int i=1;i<=n;i++){
int mx=0;
for(int j=0;j<=30;j++) if(a[i]>>j&1) mx=j;
vis[mx]|=1;
for(int j=0;j<mx;j++) if(!(a[i]>>j&1)) vis[j]|=2;
}
for(int i=1;i<=n;i++){
int mx=0;
for(int j=0;j<=30;j++) if(a[i]>>j&1) mx=j;
if(vis[mx]==3) merge(i,n+mx+1);
for(int j=0;j<mx;j++) if(!(a[i]>>j&1)&&(vis[j]==3)) merge(i,n+j+1);
}
for(int i=1;i<=n;i++) printf("%lld\n",b[find(i)]);
return 0;
}