Description
给定长为 n n n 的序列 a = ( a 1 , a 2 , ⋯ , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,⋯,an),有 m m m 个操作,分以下两种:
- modify ( l , r , k ) \operatorname{modify}(l,r,k) modify(l,r,k):对于每个 i ∈ [ l , r ] i \in [l,r] i∈[l,r] 执行 a i ← a i xor k a_i \leftarrow a_i \operatorname{xor} k ai←aixork
- query ( l , r , k ) \operatorname{query}(l,r,k) query(l,r,k):求 max b ⊆ a l ⋯ r { xor j ∈ b j xor k } \max\limits_{b \subseteq a_{l\cdots r}} \{ \mathop{\operatorname{xor}}\limits_{j\in b} j \operatorname{xor}k\} b⊆al⋯rmax{j∈bxorjxork}.
Limitations
1
≤
n
,
m
≤
5
×
1
0
4
1 \le n,m \le 5 \times 10^4
1≤n,m≤5×104
1
≤
l
≤
r
≤
n
1 \le l \le r \le n
1≤l≤r≤n
0
≤
a
i
,
k
≤
1
0
9
0 \le a_i,k \le 10^9
0≤ai,k≤109
3
s
,
125
MB
3\text{s},125\text{MB}
3s,125MB
Solution
看到区间最大异或和,想到线段树套线性基.
但
modify
\operatorname{modify}
modify 操作打不了标记,考虑转化成单点修改.
将
a
a
a 差分,设
b
1
=
a
1
b_1=a_1
b1=a1,
b
i
=
b
i
−
1
xor
a
i
(
i
>
1
)
b_i=b_{i-1} \operatorname{xor} a_i \; (i >1)
bi=bi−1xorai(i>1)。
则
a
i
=
b
1
xor
b
2
⋯
xor
b
i
a_i = b_1 \operatorname{xor} b_2 \cdots \operatorname{xor} b_i
ai=b1xorb2⋯xorbi.
由异或性质不难发现,从
a
l
⋯
r
a_{l\cdots r}
al⋯r 中选,等价于从
a
l
,
b
(
l
+
1
)
⋯
r
a_l,b_{(l+1) \cdots r}
al,b(l+1)⋯r 中选,因此两者的线性基是等价的.
因此,线段树上只需要维护
b
i
b_i
bi,单点修改,用一个树状数组维护
a
i
a_i
ai 即可。注意特判
l
=
r
l=r
l=r 的情况.
时间复杂度
O
(
n
log
n
log
2
V
)
O(n\log n \log^2 V)
O(nlognlog2V),其中
V
V
V 为值域.
Code
3.97
KB
,
30.78
s
,
13.65
MB
(in
total,
C++
20
with
O2)
3.97\text{KB},30.78\text{s},13.65\text{MB} \;\texttt{(in total, C++ 20 with O2)}
3.97KB,30.78s,13.65MB(in total, C++ 20 with O2)
重构了.
// Problem: P5607 [Ynoi2013] 无力回天 NOI2017
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5607
// Memory Limit: 125 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
namespace basis {
struct Basis {
array<int, 31> a;
Basis() {}
void insert(int x) {
for (int i = 30; i >= 0; i--) {
if (x & (1 << i)) {
if (a[i]) x ^= a[i];
else {
a[i] = x;
return;
}
}
}
}
void clear() { a.fill(0); }
int max_xor(int v = 0) {
for (int i = 30; i >= 0; i--)
if ((v ^ a[i]) > v) v ^= a[i];
return v;
}
};
Basis operator+(const Basis& lhs, const Basis& rhs) {
auto res = lhs;
for (int i = 30; i >= 0; i--) {
if (rhs.a[i]) res.insert(rhs.a[i]);
}
return res;
}
}
using basis::Basis;
inline int lowbit(int i) { return i & -i; }
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }
struct SegTree {
struct Node {
int l, r;
Basis bas;
};
int n;
vector<Node> tr;
vector<int> a, c;
SegTree() {}
SegTree(const vector<int>& _a): a(_a) {
n = a.size();
c.resize(n);
tr.resize(n << 1);
for (int i = n - 1; i >= 1; i--) a[i] ^= a[i - 1];
for (int i = 0; i < n; i++) add(i, a[i]);
build(0, 0, n - 1);
}
inline void add(int x, int v) {
for (int i = x + 1; i <= n; i += lowbit(i)) c[i - 1] ^= v;
}
inline int ask(int x) {
int ans = 0;
for (int i = x + 1; i; i -= lowbit(i)) ans ^= c[i - 1];
return ans;
}
inline void pushup(int u, int mid) {
tr[u].bas = tr[ls(mid)].bas + tr[rs(mid)].bas;
}
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
if (l == r) return tr[u].bas.insert(a[l]);
const int mid = (l + r) >> 1;
build(ls(mid), l, mid);
build(rs(mid), mid + 1, r);
pushup(u, mid);
}
void update(int u, int p, int v) {
if (tr[u].l == tr[u].r) {
tr[u].bas.clear();
return tr[u].bas.insert(a[p] ^= v);
}
const int mid = (tr[u].l + tr[u].r) >> 1;
if (p <= mid) update(ls(mid), p, v);
else update(rs(mid), p, v);
pushup(u, mid);
}
Basis query(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].bas;
const int mid = (tr[u].l + tr[u].r) >> 1;
if (r <= mid) return query(ls(mid), l, r);
else if (l > mid) return query(rs(mid), l, r);
else return query(ls(mid), l, r) + query(rs(mid), l, r);
}
inline void range_xor(int l, int r, int v) {
add(l, v);
update(0, l, v);
if (r < n - 1) {
add(r + 1, v);
update(0, r + 1, v);
}
}
inline int range_maxxor(int l, int r, int v) {
int k = ask(l);
if (l == r) return max(k ^ v, v);
auto cur = query(0, l + 1, r);
cur.insert(k);
return cur.max_xor(v);
}
};
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
scanf("%d %d", &n, &m);
vector<int> a(n);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
SegTree sgt(a);
for (int i = 0, op, l, r, v; i < m; i++) {
scanf("%d %d %d %d", &op, &l, &r, &v);
l--, r--;
if (op == 1) sgt.range_xor(l, r, v);
else printf("%d\n", sgt.range_maxxor(l, r, v));
}
return 0;
}