Address
https://www.lydsy.com/JudgeOnline/problem.php?id=3166
Solution
由于序列
a
a
的每个元素不同,因此考虑对于每个 算出:
当
l
l
和 分别满足什么条件时,区间
[l,r]
[
l
,
r
]
的次大值等于
ai
a
i
。
首先,预处理出
pre[i]
p
r
e
[
i
]
表示
i
i
前面第一个比 大的位置,
nxt[i]
n
x
t
[
i
]
表示
i
i
后面第一个比 大的位置。
显然,当
l∈[pre[i]+1,i],r∈[i,nxt[i]−1]
l
∈
[
p
r
e
[
i
]
+
1
,
i
]
,
r
∈
[
i
,
n
x
t
[
i
]
−
1
]
时,区间
[l,r]
[
l
,
r
]
的最大值为
ai
a
i
。
而如果要求
ai
a
i
为次大值,那么就要把
l
l
往左移或者把 继续往右移。
所以,可利用 二分 + RMQ ,计算
[1,pre[i]]
[
1
,
p
r
e
[
i
]
]
中最右的比
ai
a
i
大的元素位置,和
[nxt[i],n]
[
n
x
t
[
i
]
,
n
]
中最左的比
ai
a
i
大的元素位置。
于是,我们得出了
pre2[i]
p
r
e
2
[
i
]
表示
i
i
前面第二个 比 大的位置,
nxt2[i]
n
x
t
2
[
i
]
表示
i
i
后面第二个比 大的位置。
于是得出,如果
[l,r]
[
l
,
r
]
区间的次大值为
ai
a
i
,那么
l
l
和 满足:
(1)
l∈[pre2[i]+1,pre[i]],r∈[i,nxt[i]−1]
l
∈
[
p
r
e
2
[
i
]
+
1
,
p
r
e
[
i
]
]
,
r
∈
[
i
,
n
x
t
[
i
]
−
1
]
(如果
ai
a
i
前面没有比
ai
a
i
大的元素则不考虑此情况)
或(2)
l∈[pre[i]+1,i],r∈[nxt[i],nxt2[i]−1]
l
∈
[
p
r
e
[
i
]
+
1
,
i
]
,
r
∈
[
n
x
t
[
i
]
,
n
x
t
2
[
i
]
−
1
]
(如果
ai
a
i
后面没有比
ai
a
i
大的元素则不考虑此情况)
当然,我们要求最大异或,因此要让区间范围尽可能大。
因此只需要考虑区间
[pre2[i]+1,nxt[i]−1]
[
p
r
e
2
[
i
]
+
1
,
n
x
t
[
i
]
−
1
]
和
[pre[i]+1,nxt2[i]−1]
[
p
r
e
[
i
]
+
1
,
n
x
t
2
[
i
]
−
1
]
即可。
于是,问题变成了:
多组询问,每次给出一个区间
[l,r]
[
l
,
r
]
和定值
x
x
,在区间 中选一个数,使这个数与
x
x
<script type="math/tex" id="MathJax-Element-4651">x</script> 的异或值最大。
这是可持久化 Trie 的经典应用。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 5e4 + 5, M = 2e6 + 5, LogN = 20;
int n, QAQ, a[N], rt[N], stk[N], pre[N], nxt[N], top, RMQ[N][LogN], Log[N];
struct cyx {int lc, rc, id;} T[M];
void ins(int y, int &x, int val, int d, int p) {
T[x = ++QAQ] = T[y]; T[x].id = max(T[x].id, p); if (d == -1) return;
if ((val >> d) & 1) ins(T[y].rc, T[x].rc, val, d - 1, p);
else ins(T[y].lc, T[x].lc, val, d - 1, p);
}
int qmax(int l, int r) {
int x = Log[r - l + 1]; return max(RMQ[l][x], RMQ[r - (1 << x) + 1][x]);
}
int querymax(int l, int r, int x) {
int i, u = rt[r], ans = 0; Rof (i, 30, 0) {
int y = (x >> i) & 1;
if (y)
u = T[u].lc && T[T[u].lc].id >= l ? T[u].lc : (ans |= 1 << i, T[u].rc);
else u = T[u].rc && T[T[u].rc].id >= l ? (ans |= 1 << i, T[u].rc) : T[u].lc;
}
return ans ^ x;
}
int main() {
int i, j, ans = 0; n = read(); For (i, 1, n) a[i] = read();
For (i, 1, n) ins(rt[i - 1], rt[i], a[i], 30, i);
stk[top = 0] = 0; For (i, 1, n) {
while (top && a[stk[top]] < a[i]) top--;
pre[stk[++top] = i] = stk[top - 1];
}
stk[top = 0] = n + 1; Rof (i, n, 1) {
while (top && a[stk[top]] < a[i]) top--;
nxt[stk[++top] = i] = stk[top - 1];
}
Log[0] = -1; For (i, 1, n) Log[i] = Log[i >> 1] + 1;
For (i, 1, n) RMQ[i][0] = a[i]; For (j, 1, 16) For (i, 1, n - (1 << j) + 1)
RMQ[i][j] = max(RMQ[i][j - 1], RMQ[i + (1 << j - 1)][j - 1]);
For (i, 1, n) {
if (pre[i] >= 1) {
int l = 1, r = pre[i] - 1, mid;
while (l <= r) {
int mid = l + r >> 1;
if (qmax(mid, pre[i] - 1) > a[i]) l = mid + 1;
else r = mid - 1;
}
ans = max(ans, querymax(r + 1, nxt[i] - 1, a[i]));
}
if (nxt[i] <= n) {
int l = nxt[i] + 1, r = n, mid;
while (l <= r) {
int mid = l + r >> 1;
if (qmax(nxt[i] + 1, mid) > a[i]) r = mid - 1;
else l = mid + 1;
}
ans = max(ans, querymax(pre[i] + 1, l - 1, a[i]));
}
}
cout << ans << endl; return 0;
}