【ybtoj】【字典树】lowbit求和

题意

image

题解

首先考虑 lowbit 有什么特性。
lowbit(x)表示 \(x\) 的二进制最低位的 \(1\) 的所对应的值。
那么对于两个数的异或,从低到高找到二进制第一位不同的位置即可知道 lowbit 的答案。
所以考虑先把所有数插入 Trie 树中,记录每一个位置的数字有多少个。
统计答案的时候把每一个数在 Trie 树上跑一遍,每次找到 Trie 树上与当前位置不同的一边子树内的答案已经确定(即已经找到那些数最低位的 \(1\)),继续走与当前位置相同的一边子树。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1e5+10;
const ll mod = 199907210507;
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n,tot=1;
ll a[N*60],num[N*60],trie[N*60][2]; 
inline void insert(int id)
{
	int p=1;
	for(int i=0;i<=61;i++)
	{
		int ch=(a[id]>>i)&1;
		if(!trie[p][ch]) trie[p][ch]=++tot;
		p=trie[p][ch];
		num[p]++;
	}
}
inline ll lowbit(int id)
{
	int p=1;
	ll ret=0;
	for(int i=0;i<=61;i++) 
	{
		int ch=(a[id]>>i)&1;
		if(trie[p][ch^1]) (ret+=num[trie[p][ch^1]]%mod*(1ll<<i)%mod)%=mod;
		p=trie[p][ch];
	}
	return ret;
}
int main()
{	
	n=read();
	for(int i=1;i<=n;i++) 
	{
		a[i]=read();
		insert(i);
	}
	ll ans=0;
	for(int i=1;i<=n;i++) ans+=lowbit(i),ans%=mod;
	printf("%lld",ans);
	return 0;
}
posted @ 2021-09-20 23:32  conprour  阅读(195)  评论(0编辑  收藏  举报