Codeforces 665E. Beautiful Subarrays (trie树)

题意: 给定n个数A[1..n](1<=n<=10^6,0<=A[i]<=10^9),和k (1<=k<=10^9) 

求有多少个区间[L,R]使得A[L] xor A[L+1] xorxor A[R-1] xor A[R] >= k。


首先,令D[ T ] = 0 xor A[1]xor A[2] xorxor A[ T ]。

题目转化为求有多少 0<= s < t <= n 使得 D[s]^D[t] >= k。

for(int i=1;i<=n;++i){
	将D[i-1]加入某种数据结构
	在结构中搜索有多少个数在xor D[i]之后 >= k。
}

这题使用的是trie树,从根开始,每一层依次是第29位,28位到第0位的判断,左0右1的方式存入trie树。

一个数字的值,取决于它的位置,所以其实树中没有实际上存下每个数的值。

由于要求的是异或了D[i]之后的值,所以在trie树中搜索的时候要注意如果D[i]的那一位为1,则要把树当做左1右0来看待。

为了统计答案,每个节点要记录这个节点以下有多少个数。

这里用数组模拟了树形结构。


小问题:trie树需要多少个节点?         —-  2^24个

虽然树高30(根的高度算0),但是其实不需要2^31这么多的节点(根本存不下)。

首先把100万个数当做2^20.于是最坏情况是这2^20个数在第20层已经全部分开了。

需要的节点个数 = 前20层 + 后10层。

前20层:一共也才2^21节点

后10层:2^20个数,每个数每层有一个节点,一共2^20 * 10

所以一共是12* (2^20) = 3 * 2^22 < 2^24

所以节点数一定不超过2^24。



/*
	1356 ms	207000 KB
*/ 
#include <iostream>
#include <cstdio>
#include <cmath>
#define out(i) <<#i<<"="<<(i)<<"  "
#define OUT1(a1) cout out(a1) <<endl
#define OUT2(a1,a2) cout out(a1) out(a2) <<endl
#define OUT3(a1,a2,a3) cout out(a1) out(a2) out(a3)<<endl
#define maxn 1000007
#define LL long long
using namespace std;
int n,k;
int A[maxn],D[maxn],H[31];
int L[1<<24],R[1<<24],S[1<<24],P,T;
void Init(){
	L[0]=R[0]=S[0]=P=T=0;
}
void Insert(int &rt,int depth,int value){
	if(!rt){
		rt=++P;
		L[rt]=R[rt]=S[rt]=0;
	}
	++S[rt]; 
	if(depth==30) return;
	if(value&H[depth]) Insert(R[rt],depth+1,value);
	else Insert(L[rt],depth+1,value);
}
LL Query(int &rt,int depth,int value){
	if(!rt) return 0;
	if(depth==30) return S[rt];
	if(value&H[depth]){//左1右0 
		if(k&H[depth]) return Query(L[rt],depth+1,value);
		else return S[L[rt]]+Query(R[rt],depth+1,value);
	}
	else{//左0右1 
		if(k&H[depth]) return Query(R[rt],depth+1,value);
		else return S[R[rt]]+Query(L[rt],depth+1,value);
	}
}
int main(void)
{
	H[29]=1;
	for(int i=28;i>=0;--i) H[i]=H[i+1]<<1;
	while(~scanf("%d%d",&n,&k)){
		for(int i=1;i<=n;++i) scanf("%d",&A[i]);
		for(int i=1;i<=n;++i) D[i]=D[i-1]^A[i];
		Init();
		LL ANS=0;
		for(int i=1;i<=n;++i){
			Insert(T,0,D[i-1]);
			ANS+=Query(T,0,D[i]);
		}
		printf("%I64d\n",ANS);
	}
return 0;
}

    原文作者:Trie树
    原文地址: https://blog.csdn.net/zearot/article/details/51258745
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞