2021牛客多校5K King of Range

题意:给一个序列,求有多少个连续子区间的中的最大值减最小值>k。
最开始做ST表,但感觉铁TLE(但是看有群友是ST表做出来的,不知道用了什么优化)
后来做法是双指针+单调队列。
保证单调队列的方法:

=================
a[n]储存每个数
qMax,qMin 单调队列,其中qMax.front()是当前最大数的下标,qMin.front()是当前最小数的下标.
固定L=1,然后不断R++,如果a[R]要大于a[qMax.back()],就不断弹出qMax的队尾,弹到qMax为空或者a[R]小于此时的a[qMax.back()]随后就push_back( R ),这样可以保证单调队列.qMin的操作同理

==============================
a[qMax.front()] - a[qMin.front()] > k时,表明所有包含了L到R这个小区间的大区间都能满足题目要求,所以[L,R],[L,R+1],[L,R+2]一直到[L,n]
这些区间都满足,所以ans += n - r + 1;
这时我们再L++,如果移动后qMax.front的编号是L(qMax储存的是队列中最大值的编号),就要qMax.pop_front();。随后再进行一次a[qMax.front()] - a[qMin.front()] > k的判断,如果成立就能再一次ans += n - r + 1;,对于qMin的操作同理.直到判断不再成立再继续移动R
代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int a[maxn];

int main() {
	int n, m, k;
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	while (m--) {
		cin >> k;
		deque<int> qMax, qMin;
		long long ans = 0;
		for (int l = 1, r = 1; r <= n; ++ r) {//保证整个队列要单调
			while (qMax.size() && a[qMax.back()] < a[r])//只要qmax最尾部的数小于a[r],就不断弹出
				qMax.pop_back();
			qMax.push_back(r);//然后将r放进去
			while (qMin.size() && a[qMin.back()] > a[r])
				qMin.pop_back();
			qMin.push_back(r);
			
			while (a[qMax.front()] - a[qMin.front()] > k) {
				ans +=(long long) n - r + 1;//只要包含了l到r的区间都成立
				l ++;
				if (qMax.front() < l)//向右移动l,如果队列最大值的编号是l就弹出
					qMax.pop_front();
				if (qMin.front() < l)
					qMin.pop_front();
			}
		}
		printf("%lld\n", ans);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值