【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;
}
posted @ 2021-01-25 13:38  Jayun  阅读(94)  评论(0编辑  收藏  举报