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 }
原文地址:https://www.cnblogs.com/hxer/p/5563215.html