【YBTOJ】【SPOJ 7739】【Luogu P4392】[BOI2007]Sound 静音问题
链接:
题目大意:
求一段数列中,长度为 \(m\) 的区间最大值减最小值小于等于 \(c\) 的区间有多少个。
正文:
毕竟没有修改的操作,是静态的,用线段树或树状数组显然没必要。提供 ST 表的解法。
这题要求最大值和最小值,那么就同时开两个数组,分别存最大和最小就行了。时间复杂度 \(O(n\log m)\)。
代码:
int n, m, c;
int Max[N][12], Min[N][12];
int secMax(int l, int r)
{
int k = log2(r - l + 1);
return max(Max[l][k], Max[r - (1 << k) + 1][k]);
}
int secMin(int l, int r)
{
int k = log2(r - l + 1);
return min(Min[l][k], Min[r - (1 << k) + 1][k]);
}
int main()
{
scanf ("%d%d%d", &n, &m, &c);
int lg = log2(m);
for(int i = 1; i <= n; i++)
scanf ("%d", &Max[i][0]), Min[i][0] = Max[i][0];
for(int j = 1; j <= lg; j++)
for(int i = 1; i + (1 << j) - 1 <= n; 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]);
int flag = 1;
for (int i = 1; i + m - 1 <= n; i++)
if (secMax(i, i + m - 1) - secMin(i, i + m - 1) <= c)
printf ("%d\n", i), flag = 0;
if (flag) printf("NONE\n");
return 0;
}