Solution
首先要预处理出每一个位置的上一个与当前位置的数相同的位置,然后就可以利用它求出(pos[i]),表示以第(i)个数为结尾的最长完美序列的起始位置。然后就可以求出每一个位置往前最多可以选多少个数,我们用RMQ来维护一下这个东西
询问的时候,由于(pos)单调不降,直接在([l, r])中二分一下找到最靠前的一个位置使得(pos[mid] > l),因为要保证选的数要在([l, r])的范围内。所以(ans = max(mid - l, Max(mid, r))),(Max(l, r))表示RMQ维护的最大值
Code
#include <bits/stdc++.h>
using namespace std;
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef pair<int, int> pii;
inline int read() {
int sum = 0, fg = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
return fg * sum;
}
const int maxn = 2e5 + 10;
const int maxm = 2e6 + 10;
int n, m;
int lst[maxm], pos[maxn], f[maxn], Max[maxn][18], Pow[18], Log[maxn];
int find(int l, int r) {
int L = l; /**/
while (l <= r) {
int mid = (l + r) >> 1;
if (pos[mid] > L) r = mid - 1;
else l = mid + 1;
}
return r + 1;
}
int query(int l, int r) {
int x = Log[r - l + 1];
return max(Max[r][x], Max[l + Pow[x] - 1][x]);
}
int main() {
#ifdef xunzhen
freopen("perfect.in", "r", stdin);
freopen("perfect.out", "w", stdout);
#endif
n = read(); m = read();
Pow[0] = 1;
for (int i = 1; i <= 17; i++) Pow[i] = Pow[i - 1] << 1;
for (int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;
for (int i = 1; i <= n; i++) {
int k = read() + (int)1e6;
pos[i] = max(pos[i - 1], lst[k] + 1);
lst[k] = i;
f[i] = i - pos[i] + 1;
}
for (int i = 1; i <= n; i++) {
Max[i][0] = f[i];
for (int j = 1; j <= 17; j++) {
int pre = max(i - Pow[j - 1], 0); /**/
Max[i][j] = max(Max[i][j - 1], Max[pre][j - 1]);
}
}
while (m--) {
int l = read() + 1, r = read() + 1;
int res = find(l, r), ans = res - l;
if (res <= r) ans = max(ans, query(res, r));
printf("%d
", ans);
}
return 0;
}
Summary
这道题是真的坑 其实是我坑...
这道题我不得不承认,还是有一点难度的
RMQ一定要经常打一下,要不然会有很多细节写错
(debug):打错的地方已在代码中(mark)