01Trie学习笔记

零、有关Trie

前置知识:Trie学习笔记

小投票(见文章底部)。

一、问题引入:Beautiful Subarrays

洛谷题面CF原版题面

二、解决问题

这次,我们可以使用前缀和解决问题。

但是,当我们求出其前缀和时,如何知道答案是多少?

这就需要用到 01Trie 了。

三、新算法: 01Trie

01Trie,顾名思义,这是个只有字符'0','1'的 Trie。

提到 01,我们首先想到二进制。

你说的没错,这个算法就是存储二进制的 Trie。

四、统计答案

插入和查询见前置知识。

统计答案较为复杂。  

假设我们遍历到了第 i 层,求有几个数异或 a 大于等于 k。

1. k 的二进制的第 i 为是 1

那么答案的这一位是能与 a 的这一位不同(异或值为1)。

2. k 的二进制的第 i 为是 0

那么情况有两种:

  • 答案的这一位是能 a 的这一位不同(异或值为1)。
  • 答案的这一位是能 a 的这一位相同(异或值为0)。
  • 注意,在第一种情况中,所有这个子树里的数都行,所以可以不去枚举。

五、代码

#include <bits/stdc++.h>
using namespace std;
#define N 30000010
int tree[N][2],cnt[N],tot=1;
int n,k,sum;
long long ans;
struct node{
	void insert(int x){
		int now=1;
		for (int i=30; i>=0; i--){
			int c=(x>>i)&1;
			if (tree[now][c]==0){
				tree[now][c]=++tot;
			}now=tree[now][c]; cnt[now]++;
		}
	}int ask(int x){
		int now=1,ans=0;
		for (int i=30; i>=0; i--){
			int c=(x>>i)&1,d=(k>>i)&1;
			if (d==0) ans+=cnt[tree[now][c^1]];
			now=tree[now][c^d];
		}return ans+cnt[now];
	}
}t;
signed main(){
	cin>>n>>k;
	for (int i=1; i<=n; i++){
		t.insert(sum);
		int x; cin>>x; sum^=x; 
		ans+=t.ask(sum);
	}cout<<ans;
} 

 

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值