#Trie# [Ybtoj NOIP2020 模拟赛 B 组 Day7] 区间异或

Title

大意:给一个区间,询问有多少了区间满足异或和不小于给定的正整数 K K K


Solution

注意一开始trie要插入初始值0

s [ i ] s[i] s[i]表示 [ 1 , i ] [1,i] [1,i]的异或和, [ l , r ] [l,r] [l,r]的异或和相当于 s [ r ]   x o r   s [ l − 1 ] s[r]\ xor\ s[l-1] s[r] xor s[l1]

可以用 T r i e Trie Trie表示前缀 x o r xor xor

如何求大于等于 K K K的区间数,可以在查询的时候,强制前面某些位相同,然后反转下一位。


Code

#include<cstdio> 
#include<algorithm>
#include<cstring>
#include<string>
#define ll long long 
#define rep(i,x,y) for(int i=x;i<=y;i++)
using namespace std; 
const int N=1e5+5; 
int read(){
	int p=0,f=1; char c=getchar(); 
	while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}
	while (isdigit(c)) p=(p<<3)+(p<<1)+c-48,c=getchar(); 
	return p*f; 
}
int T; 
int n,K; 
ll ans,Qw; 
struct node{
	int t[N][2],cnt[N],tot; 
	void clear(){
		cnt[1]=t[1][1]=t[1][0]=0; tot=1;
	}
	void insert(int x){
		int p=1; 
		for(int i=29;~i;--i){
			int w=(x>>i)&1; 
			if (!t[p][w]){
				t[p][w]=++tot; cnt[tot]=0; t[tot][0]=t[tot][1]=0; 
			}
			++cnt[p],p=t[p][w]; 
		}
		++cnt[p]; 
	}
	ll query(int x){
		int p=1; ll sum=0; 
		for(int i=29;~i;--i){
			if (!p) return sum; 
			if ((x>>i)&1){
				if ((K>>i)&1) p=t[p][0]; 
				else sum+=cnt[t[p][0]],p=t[p][1]; 
			} else {
				if ((K>>i)&1) p=t[p][1]; 
				else sum+=cnt[t[p][1]],p=t[p][0]; 
			}
		}
		return sum+cnt[p]; 
	}
}Trie;
int main(){
	freopen("xor.in","r",stdin); 
	freopen("xor.out","w",stdout); 
	T=read(); 
	while (T--){
		Trie.clear(); 
		n=read(),K=read(); 
		ans=Qw=0; Trie.insert(Qw); 
		rep(i,1,n) {
			Qw^=read(); 
			ans+=Trie.query(Qw); 
			Trie.insert(Qw); 
		}
		printf("%lld\n",ans); 
	}
	return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值