Equal XOR Segments
题目描述
如果可以将数组分成 k > 1 k>1 k>1 部分,使得每部分的值 bitwise XOR 都相等,那么我们就称该数组 x 1 , … , x m x_1,\dots,x_m x1,…,xm 为有意思的数组。
更正式地说,你必须把数组 x x x 分成 k k k 个连续的部分, x x x 中的每个元素都必须准确地属于 1 1 1 个部分。设 y 1 , … , y k y_1,\dots,y_k y1,…,yk 分别是各部分元素的 XOR。那么 y 1 = y 2 = ⋯ = y k y_1=y_2=\dots=y_k y1=y2=⋯=yk 必须满足。
例如,如果是 x = [ 1 , 1 , 2 , 3 , 0 ] x = [1, 1, 2, 3, 0] x=[1,1,2,3,0] ,可以将其拆分如下: [ 1 ] , [ 1 ] , [ 2 , 3 , 0 ] [\color{blue}1], [\color{green}1], [\color{red}2, \color{red}3, \color{red}0] [1],[1],[2,3,0] 。其满足 1 = 1 = 2 ⊕ 3 ⊕ 0 \color{blue}1=\color{green}1=\color{red}2 \oplus \color{red}3\oplus \color{red}0 1=1=2⊕3⊕0 ,是有意思的数组。
给你一个数组 a 1 , … , a n a_1,\dots,a_n a1,…,an 。你的任务是回答 q q q 个查询:
- 对于固定的 l l l , r r r , 判断子数组 a l , a l + 1 , … , a r a_l,a_{l+1},\dots,a_r al,al+1,…,ar 是否有趣。
输入描述
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1\le t\le 10^4 1≤t≤104 ) - 测试用例数。
每个测试用例的第一行包含两个整数 n n n 和 q q q ( 2 ≤ n ≤ 2 ⋅ 1 0 5 2 \le n \le 2 \cdot 10^5 2≤n≤2⋅105 , 1 ≤ q ≤ 2 ⋅ 1 0 5 1 \le q \le 2 \cdot 10^5 1≤q≤2⋅105 )–分别是数组中的元素个数和查询次数。
下一行包含 n n n 个整数 a 1 , … , a n a_1,\dots,a_n a1,…,an ( 0 ≤ a i < 2 30 0 \le a_i < 2^{30} 0≤ai<230 ) - 数组元素。
接下来的每行 q q q 包含两个整数 l l l 和 r r r ( 1 ≤ l < r ≤ n 1 \le l < r \le n 1≤l<r≤n ),分别描述查询。
保证所有测试用例中 n n n 的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105 。
保证所有测试用例中 q q q 的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105 。
输出描述
对于每个查询,如果子数组有趣,则输出一行 “YES”,否则输出一行 “NO”。
样例输入
4
5 5
1 1 2 3 0
1 5
2 4
3 5
1 3
3 4
5 5
1 2 3 4 5
1 5
2 4
3 5
1 3
2 3
7 4
12 9 10 9 10 11 9
1 5
1 7
2 6
2 7
11 4
0 0 1 0 0 1 0 1 1 0 1
1 2
2 5
6 9
7 11
样例输出
YES
YES
NO
NO
NO
YES
NO
NO
YES
NO
NO
NO
NO
NO
YES
NO
YES
YES
原题
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
int n, q;
cin >> n >> q;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
// b数组为a的前缀位异或
vector<int> b(n + 1, 0);
// 用map离散存储等于某值的所有索引位置
map<int, vector<int>> idx;
idx[0].push_back(0);
for (int i = 1; i <= n; i++)
{
b[i] = b[i - 1] ^ a[i];
idx[b[i]].push_back(i);
}
// 处理询问
int l, r;
while (q--)
{
cin >> l >> r;
// 假如k=2,则需要b[l-1]^b[t]==b[t]^b[r]即b[l-1]==b[r]
if (b[l - 1] == b[r])
{
cout << "YES" << '\n';
continue;
}
// 假如k=3,则需要b[l-1]^b[s]==b[s]^b[t]==b[t]^b[r]即b[l-1]==b[t]且b[s]==b[r]
// 问题转化为找出两点s,t满足l<=s<t<r,b[l-1]==b[t]且b[s]==b[r]
// 二分查找值等于b[r]中的大于l-1位置的位置
int s = lower_bound(idx[b[r]].begin(), idx[b[r]].end(), l) - idx[b[r]].begin();
if (s == idx[b[r]].size() || idx[b[r]][s] >= r) // 没找到或者找到的位置大于等于r,都不满足
{
cout << "NO" << '\n';
continue;
}
// 既然已找到s的位置,那么二分查找值等于b[l-1]中的大于s位置的位置
int t = lower_bound(idx[b[l - 1]].begin(), idx[b[l - 1]].end(), idx[b[r]][s] + 1) - idx[b[l - 1]].begin();
if (t == idx[b[l - 1]].size() || idx[b[l - 1]][t] >= r) // 没找到或者找到的位置大于等于r,都不满足
{
cout << "NO" << '\n';
}
else
{
cout << "YES" << '\n';
}
}
cout << '\n';
}
return 0;
}

971

被折叠的 条评论
为什么被折叠?



