单调队列训练

单调队列感觉还是用的不熟练, 这几天再找几个题做做,顺便再练一练斜率优化.

练习1. Luogu P3522 [POI2011]TEM-Temperature

大意: n个数, 第$i$个数可以替换为$[L_i,R_i]$中的任意一个, 求最长连续非降序列的长度

考虑贪心, 每次选择尽量小的数, 对于第$i$个数, 如果$R_i$小于上次选择的数, 发现这里取什么贪心就不能判断了, 所以就要用单调队列辣.

其实就是枚举右端点, 单队求出最小的左端点值.

假设现在维护的区间为$[l,r]$, 新添加一个点$r+1$, 假设$[l,r]$中存在一点$x$, 并且$L_x>R_{r+1}$的话, 那么区间$[l,x]$的点都要删除, 也就是说要找到最大的$x$满足$L_x>R_{r+1}$, 所以维护一个关于L的递减的单队即可.

#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
#include <set>
#include <queue>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;

const int N = 1e6+10;
int n;
int L[N], R[N];

int main() {
	scanf("%d", &n);
	REP(i,1,n) scanf("%d%d",L+i,R+i);
	deque<int> q;
	int ans = 0, pos = 1;
	REP(i,1,n) {
		while (q.size()&&L[q.front()]>R[i]) pos = q.front()+1, q.pop_front();
		ans = max(ans, i-pos+1);
		while (q.size()&&L[q.back()]<=L[i]) q.pop_back();
		q.push_back(i);
	}
	printf("%d\n", ans);
}

猜你喜欢

转载自www.cnblogs.com/uid001/p/10447836.html