题意
给定一个非负整数序列
a
a
a,初始长度
n
n
n。两种操作,每种多次:
A x:在序列末尾+一个数x
Q l r x:询问操作,找到一个位置
p
p
p,满足
l
≤
p
≤
r
l\le p\le r
l≤p≤r,使得:
a
[
p
]
⊕
a
[
p
+
1
]
⊕
.
.
.
⊕
a
[
N
]
⊕
x
a[p]\oplus a[p+1]\oplus...\oplus a[N]\oplus x
a[p]⊕a[p+1]⊕...⊕a[N]⊕x最大,输出最大值。
分析
异或操作满足前缀和的性质, s s s为异或前缀和数组,询问操作相当于 a [ N ] ⊕ x ⊕ a [ p − 1 ] a[N]\oplus x\oplus a[p-1] a[N]⊕x⊕a[p−1]最大,并且满足 [ l , r ] [l,r] [l,r]区间限制。 a [ N ] ⊕ x a[N]\oplus x a[N]⊕x为定值 = v a l =val =val,问题转化为每次在 p ∈ [ l − 1 , r − 1 ] p\in[l-1,r-1] p∈[l−1,r−1],使得 s [ p ] ⊕ v a l s[p]\oplus val s[p]⊕val最大。
可以建立可持久化字典树,每次贪心的选取与 v a l val val相反的当前位。为了满足右区间的限制:每次询问时从 r o o t [ r − 1 ] root[r-1] root[r−1]进行询问,为满足左区间限制,对每个节点维护一个 m a x m maxm maxm,表示当前节点为根的子树中下标最大值,每次查询时进行比较即可。
代码
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <iomanip>
#include <map>
#include <cstdio>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll ,ll > pii;
#define endl '\n'
ll gcd(ll a, ll b){
return b == 0 ? a : gcd(b, a % b);
}
void input(){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
}
inline ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
const ll N = 6e5+10, M = N * 2, inf = 1e8;
// 对前缀和建可持久化字典树
ll n, m, a[N], s[N];
ll tr[N * 27][2], maxm[N * 27], root[N], idx;
void insert(ll i, ll dep, ll p, ll q){
if(dep == -1){
maxm[q] = i;
return;
}
ll v = (s[i] >> dep) & 1;
if(p) tr[q][v^1] = tr[p][v^1];
tr[q][v] = ++idx;
insert(i, dep-1, tr[p][v], tr[q][v]);
maxm[q] = max(maxm[tr[q][1]], maxm[tr[q][0]]);
}
ll query(ll root, ll c,ll l){
ll p = root;
for(ll i = 25; i >= 0; i--){
ll v = (c>>i) & 1;
if(maxm[tr[p][v^1]] >= l) p = tr[p][v^1];
else p = tr[p][v];
}
return c ^ s[maxm[p]];
}
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>m;
maxm[0] = -1, root[0] = ++idx;
insert(0, 25, 0, root[0]);
for(ll i = 1; i <= n; i++) {
cin>>a[i]; s[i] = s[i-1] ^ a[i];
root[i] = ++idx;
insert(i, 25, root[i-1], root[i]);
}
while(m--){
char op; cin>>op;
if(op == 'A'){
ll x; cin>>x;
n++; root[n] = ++idx;
s[n] = s[n-1] ^ x;
insert(n, 25, root[n-1], root[n]);
}else{
ll l, r, x; cin>>l>>r>>x;
cout<<query(root[r-1], x^s[n], l-1)<<endl;
}
}
return 0;
}