题目传送门bzoj3261 题 目 传 送 门 b z o j 3261
题目
3261:最大异或和 3261 : 最 大 异 或 和
TimeLimit:10Sec
T
i
m
e
L
i
m
i
t
:
10
S
e
c
MemoryLimit:512MB
M
e
m
o
r
y
L
i
m
i
t
:
512
M
B
Description D e s c r i p t i o n
给定一个非负整数序列
a
a
,初始长度为
N
N
。
有个操作,有以下两种操作类型:
1
1
、
x
x
:添加操作,表示在序列末尾添加一个数,序列的长度
N+1
N
+
1
。
2
2
、
l
l
x
x
:询问操作,你需要找到一个位置,满足
l≤p≤r
l
≤
p
≤
r
,使得:
a[p]
a
[
p
]
xor
x
o
r
a[p+1]
a
[
p
+
1
]
xor
x
o
r
...
.
.
.
xor
x
o
r
a[N]
a
[
N
]
xor
x
o
r
x
x
最大,输出最大是多少。
第一行包含两个整数
N
N
,,含义如问题描述所示。
第二行包含
N
N
个非负整数,表示初始的序列。
接下来
M
M
行,每行描述一个操作,格式如题面所述。
假设询问操作有 T T 个,则输出应该有行,每行一个整数表示询问的答案。
SampleInput S a m p l e I n p u t
5 5
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6
SampleOutput S a m p l e O u t p u t
4
5
6
对于测试点
1−2,N,M≤5
1
−
2
,
N
,
M
≤
5
。
对于测试点
3−7,N,M≤80000
3
−
7
,
N
,
M
≤
80000
。
对于测试点
8−10,N,M≤300000
8
−
10
,
N
,
M
≤
300000
。
其中测试点
1,3,5,7,9
1
,
3
,
5
,
7
,
9
保证没有修改操作。
0≤a[i]≤107 0 ≤ a [ i ] ≤ 10 7 。
题解
看到
xor
x
o
r
,本能反应就是按位
xor
x
o
r
。
首先用最裸的做法,用前缀和处理一下。
设
s[i]
s
[
i
]
=
=
xor
x
o
r
a[2]
a
[
2
]
xor
x
o
r
...
.
.
.
xor
x
o
r
a[i]
a
[
i
]
则
a[p]
a
[
p
]
xor
x
o
r
a[p+1]
a
[
p
+
1
]
xor
x
o
r
...
.
.
.
xor
x
o
r
a[N]
a
[
N
]
xor
x
o
r
x
x
s[p−1]
s
[
p
−
1
]
xor
x
o
r
s[N]
s
[
N
]
xor
x
o
r
x
x
添加,询问
O(N)
O
(
N
)
,时间
O(MN)
O
(
M
N
)
,空间
O(N)
O
(
N
)
。
观察
N
N
的取值范围,可以想到用。
构造一棵可持久化
Trie
T
r
i
e
,询问时询问
s[l−1]
s
[
l
−
1
]
到
s[r−1]
s
[
r
−
1
]
与
s[N]
s
[
N
]
xor
x
o
r
x
x
。
因为高位的比低位的
1
1
加起来还要大,所以高位的先取。
添加
O(logN)
O
(
l
o
g
N
)
,询问
O(logN)
O
(
l
o
g
N
)
,时间
O(MlogN)
O
(
M
l
o
g
N
)
,空间
O(MlogN)
O
(
M
l
o
g
N
)
。
总结
看到异或,本能反应就是位运算的方法。
例如:按位
xor
x
o
r
,数位
DP
D
P
,
Trie
T
r
i
e
,可持久化
Trie
T
r
i
e
……
这样的关于异或的题目,一般情况下,都可以用
O(logN)
O
(
l
o
g
N
)
的时间解决……
简单地说,就是先想
Trie
T
r
i
e
。做不了,那我也没办法了……
标程
#include <bits/stdc++.h>
using namespace std;
const int N = 6e5 + 50;
struct tree{
int c[2], cnt;
}t[N * 25];
int top, s[25], a[N], b[N], r[N];
int update(int y, int z)
{
int ret = ++top, x = ret;
for (int i = 23; i >= 0; i--)
{
t[x] = t[y]; t[x].cnt++;
bool tmp = (z >> i) & 1;
y = t[y].c[tmp];
x = t[x].c[tmp] = ++top;
}
t[x] = t[y]; t[x].cnt++;
return ret;
}
int query(int x, int y, int z)
{
int ret = 0;
for (int i = 23; i >= 0; i--)
{
bool tmp = (z >> i) & 1;
if (t[t[x].c[tmp ^ 1]].cnt != t[t[y].c[tmp ^ 1]].cnt)
{ret += s[i]; x = t[x].c[tmp ^ 1]; y = t[y].c[tmp ^ 1];}
else {x = t[x].c[tmp]; y = t[y].c[tmp];}
}
return ret;
}
int main()
{
int n, m; s[0] = 1;
for (int i = 1; i <= 23; i++)
s[i] = s[i - 1] << 1;
scanf("%d%d", &n, &m); n++;
r[1] = update(r[0], 0);
for (int i = 2; i <= n; i++)
{
scanf("%d", &a[i]);
b[i] = b[i - 1] ^ a[i];
r[i] = update(r[i - 1], b[i]);
}
while (m--)
{
char c[10]; scanf("%s", c);
if (c[0] == 'A')
{
scanf("%d", &a[++n]);
b[n] = b[n - 1] ^ a[n];
r[n] = update(r[n - 1], b[n]);
}
else
{
int x, y, z; scanf("%d%d%d", &x, &y, &z);
printf("%d\n", query(r[x - 1], r[y], b[n] ^ z));
}
}
return 0;
}