题意: 给出一个数组, 长度为1e5, 1次询问, 给出一个上界R, 一个下界L, 问最大值减最小值差∈[L, R]的区间最长是多少.
思路: RMQ当然可以维护M-m, 但是因为对M-m有两个限制, 没有单调性就不能二分解决..只能用我不太熟悉的尺取了.
尺取的具体思路见代码:
// a~b如果M-m>上界, a~c只会增大M, 减小m
// 增大M减小m后, 更不可能合法.
// 所以只要当前区间M-m>上界, 不需要再考虑左端点不动的其他区间
// 1~n枚举右端点的位置i, 表示在已经考虑右端点<i的所有区间.
// 如果当前区间M-m>上界, 左端点pos+=1(此后的合法区间左端点不可能<=pos)
// 检查当前区间合法, 更新ans
// 右端点更新i++
for (int i = 1; i <= n; i++) {
int tmp = RMQ::RMQ_max(pos, i) - RMQ::RMQ_min(pos, i);
if (tmp > k)pos++;
tmp = RMQ::RMQ_max(pos, i) - RMQ::RMQ_min(pos, i);
if (tmp <= k && tmp >= m) {
ans = max(ans, i - pos + 1);
}
}
#include<bits/stdc++.h>
using namespace std;
const int M = 2e5 + 5;
namespace RMQ {
//可以从0也可以从 1开始,30应该能使用 1e6以内的
const int MX = M;
const int P = 17;
int MIN[MX][P], MAX[MX][P];
int lg[MX];
int A[MX];
void RMQ_init1() {//预处理使RMQ的复杂度变为O(1)
for (int i = 1, j = 0; i < MX; ++i) {
if (i <= (1 << (j + 1)))
lg[i] = j;
else
lg[i] = ++j;
}
}
void RMQ_init2(int n) {
for (int i = 0; i < n + 1; ++i) {
MAX[i][0] = MIN[i][0] = A[i];
}
for (int j = 1; (1 << j) <= n + 1; ++j) {
for (int i = 0; i + (1 << j) - 1 < n + 1; ++i) {
MAX[i][j] = max(MAX[i][j - 1], MAX[i + (1 << (j - 1))][j - 1]);
MIN[i][j] = min(MIN[i][j - 1], MIN[i + (1 << (j - 1))][j - 1]);
}
}
}
//要保证L<=R
int RMQ_min(int L, int R) {
int k = lg[R - L + 1];
//int k =0;while((1<<(k+1))<R-L+1) k++;//用这个的话, 就不需要先算log了
return min(MIN[L][k], MIN[R - (1 << k) + 1][k]);
}
int RMQ_max(int L, int R) {
int k = lg[R - L + 1];
//int k =0;while((1<<(k+1))<R-L+1) k++;//用这个的话, 就不需要先算log了
return max(MAX[L][k], MAX[R - (1 << k) + 1][k]);
}
}
int n, m, k;
bool jug(int len) {
for (int s = 1; s + len - 1 <= n; s++) {
int t = s + len - 1;
int tmp = RMQ::RMQ_max(s, t) - RMQ::RMQ_min(s, t);
if (tmp >= m) {
return true;
}
}
return false;
}
bool jug2(int len) {
for (int s = 1; s + len - 1 <= n; s++) {
int t = s + len - 1;
int tmp = RMQ::RMQ_max(s, t) - RMQ::RMQ_min(s, t);
if (tmp <= k) {
return true;
}
}
return false;
}
int ans;
inline int read() {
int ret = 0, c, f = 1;
for (c = getchar(); !(isdigit(c) || c == '-'); c = getchar());
if (c == '-') f = -1, c = getchar();
for (; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
if (f < 0) ret = -ret;
return ret;
}
void init() {
RMQ::RMQ_init1();
while (~scanf("%d%d%d", &n, &m, &k)) {
ans = 0;
for (int i = 1; i <= n; i++)RMQ::A[i] = read();
RMQ::RMQ_init2(n);
int pos = 1;
// a~b如果M-m>上界, a~c只会增大M, 减小m
// 增大M减小m后, 更不可能合法.
// 所以只要当前区间M-m>上界, 不需要再考虑左端点不动的其他区间
// 1~n枚举右端点的位置i, 表示在已经考虑右端点<i的所有区间.
// 如果当前区间M-m>上界, 左端点pos+=1(此后的合法区间左端点不可能<=pos)
// 检查当前区间合法, 更新ans
// 右端点更新i++
for (int i = 1; i <= n; i++) {
int tmp = RMQ::RMQ_max(pos, i) - RMQ::RMQ_min(pos, i);
if (tmp > k)pos++;
tmp = RMQ::RMQ_max(pos, i) - RMQ::RMQ_min(pos, i);
if (tmp <= k && tmp >= m) {
ans = max(ans, i - pos + 1);
}
}
printf("%d\n", ans);
}
}
int main() {
init();
return 0;
}