Educational Codeforces Round 12 E. Beautiful Subarrays 预处理+二叉树优化
链接:http://codeforces.com/contest/665/problem/E
题意:求规模为1e6数组中,连续子串xor值大于等于k值的子串数;
思路:xor为和模2的性质,所以先预处理之后,可以枚举这种确实子串区间的方法为O(n^2);
优化?把每一个前缀xor扔到二叉树中,从根节点出发,以高位前缀值的二进制数构造一颗二叉树,这样就可以在构造的时候,实现对子树节点个数的求解;之后在线求解到当前节点的可选的前缀xor的个数,
即以k为主线
如果当前位k为1,则在前缀二叉树中只能找和当前节点xor出结果为1的节点,并且这个节点的num值不能加到结果中;
如果是当前位k为0,则直接加上xor结果为1的节点个数(num),方向不变;
注:最后一个叶子节点不能求到,要在最后加上叶子节点的个数
时间复杂度为O(nlgn)
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int MAXN = 11234567; 5 int num[MAXN],tot = 1,d[MAXN][2],n,k; 6 void update(int a) 7 { 8 for(int i = 30, p = 1;i >= 0;i--){ 9 if(d[p][(a>>i)&1] == 0) d[p][(a>>i)&1] = ++tot; 10 p = d[p][(a>>i)&1]; 11 num[p]++; 12 } 13 } 14 long long solve(int x) 15 { 16 long long ans = 0, p = 1; 17 for(int i = 30;i >= 0;i--){ 18 if((k>>i)&1) p = d[p][1^((x>>i)&1)]; 19 else{ 20 ans += num[d[p][1^((x>>i)&1)]]; 21 p = d[p][(x>>i)&1]; 22 } 23 } 24 return ans + num[p]; // leaf 25 } 26 int main() 27 { 28 cin>>n>>k; 29 int prefix = 0,x; 30 long long ans = 0; 31 for(int i = 0;i < n;i++){ 32 update(prefix); 33 scanf("%d",&x); 34 prefix ^= x; 35 ans += solve(prefix); 36 } 37 printf("%I64d",ans); 38 }