acwing3488 常规异或前缀树+更新策略

发布时间 2023-07-21 10:26:56作者: LegendN

https://www.acwing.com/problem/content/3488/

不同于一般的子数组异或和(异或前缀和+前缀树),本题对子数组长度作了限制。

依旧考虑维护一颗前缀树,记录前缀树的每个节点在当前状态是否可达。只是规定树内涉及的节点规模不大于m。

可以发现,我们在[x, x + m - 1]区间,和[x + 1, x + m]区间作检索,并不需要O(m)的处理。

只需要去除x节点,加上x+m节点,并对x+m节点查询即可(由于异或的可交换性)。

还有一个小细节,例如要求[l, r]的异或前缀和,我们用data[r] ^ data[l - 1]。

那么对于前m项,我们实际所需维护的应是m+1个数,包括0,这样才能保证前m个同时取到。

同理,对于[2, 2 + m - 1],我们实际需要的前缀和应包括[1, 2 + m - 1]。因而在加上2+m-1这一项前,应确保第0项(含0)前的元素均被删去。

所以对于i > m的第i次维护,应add(i),并del(i - m - 1)。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<vector>
 4 #include<string>
 5 #include<queue> 
 6 #include<map>
 7 #include<set>
 8 #define ll long long
 9 #define pii pair<int, int>
10 using namespace std;
11 const int N = 1E5 + 10;
12 const ll INF = INT64_MAX;
13 using namespace std;
14 
15 int m, n, pre[N], a[N];
16 int t[N * 31][2];
17 int check[N * 31];
18 int cnt = 0;
19 
20 void build(int x, int u)
21 {
22     for(int i = 30 ; i >= 0 ; i--) {
23         int tmp = (1 << i) & x;
24         if(tmp) {
25             if(!t[u][1]) {
26                 t[u][1] = ++cnt;
27             }
28             u = t[u][1];
29         }else {
30             if(!t[u][0]) {
31                 t[u][0] = ++cnt;
32             }
33             u = t[u][0];
34         }
35         check[u]++;
36     }
37 }
38 
39 int find(int x, int u)
40 {
41     int res = 0;
42     for(int i = 30 ; i >= 0 ; i--) {
43         int tmp = (1 << i) & x;
44         if(tmp) { // x此位为1 
45             if(check[t[u][0]]) {
46                 u = t[u][0];
47             }else {
48                 u = t[u][1];
49                 res |= (1 << i);
50             }
51         }else {
52             if(check[t[u][1]]) {
53                 u = t[u][1];
54                 res |= (1 << i);
55             }else {
56                 u = t[u][0];
57             }
58         }
59     }
60     return res;
61 }
62 
63 void del(int x, int u)
64 {
65     for(int i = 30 ; i >= 0 ; i--) {
66         int tmp = (1 << i) & x;
67         if(tmp) {
68             u = t[u][1];
69         }else {
70             u = t[u][0];
71         }
72         check[u]--;
73     }
74 }
75 
76 int main()
77 {
78     ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
79     cin >> n >> m;
80     for(int i = 1 ; i <= n ; i++) {
81         cin >> a[i];
82         pre[i] = pre[i - 1] ^ a[i];
83     }
84     int ans = 0;
85     for(int i = 0 ; i <= n ; i++) {
86         if(i > m) {
87             del(pre[i - m - 1], 0);
88         }
89         build(pre[i], 0);
90         ans = max(ans, find(pre[i], 0) ^ pre[i]);
91     }
92     cout << ans << endl;
93     
94     return 0;
95 }
96 /*
97     acwing 3488
98 */