单调队列

单调队列~~~~

同时食用效果更佳

1.单调队列可以干嘛?

求区间最值

好像就没啥了

2.不过我们简单举个例子——

玩卡牌类游戏的时候,每个角色有对应的绝对战力值,但玩家选角色上阵的时候有时不只是会看每个角色的绝对战力值 还会看好不好看啥的 (lsp了)
对于那些 又丑又弱 的角色,玩家是绝对不会选的
单调队列就是这个思想
一组数据中,取区间极值,如果某个值的下标小,又取不到极值,那肯定是看都不会选的(简而言之就是在这个值所在的区间中,它永远取不到极值那么就可以彻底排除了)

3.直接上模板代码

//数组实现
#include 
#define MAXN 2000005
using namespace std;

struct Num{
    int index,x;//需要记录单调队列内每个数的入队时间(index)和大小(x)
};

int a[MAXN]; //原数组
Num q[MAXN]; //单调队列 

int main(void){
    int n,m; //n表示序列长度,m表示滑动窗口长度
    int front,back; //front,back分别表示队头、队尾位置
    //输入
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    //问题解决
    front=1;
    back=0;//初始化队头队尾位置,队头>队尾表示队空
    for (int i=1;i<=n;i++){
        //先输出数a[i]前的最小值
        if (front>back) //q空,即a[i]前没有元素
            printf("0\n");
        else { //否则判断队头是否需要出队并输出范围内的队头
            if (q[front].index+m=a[i]) 
        //当队列非空时,不断弹出队尾比当前元素大的元素
            back--;
        back++;
        q[back].x=a[i];
        q[back].index=i;//将当前元素入队
        //注意:当前元素无论如何都会入队(想想为什么)
    }
    return 0;
}

4.来道例题

原题洛谷P1714

解析

区间最值前缀和走一波
所以我们要求的就是 c++max(sum[i]-sum[j])(j是以i为起点的,在区间范围内可能的所有重点)所以代码就出来了
有点像贪心
正解代码如下:

#include
#include
using namespace std;
const int N=5e5+10,INF=1e9;
int sum[N],q[N];
int main()
{
	int n,m;scanf("%d%d",&n,&m);
	for (register int i=1;i<=n;++i)
	{
		int x;scanf("%d",&x);
		sum[i]=sum[i-1]+x;
	}
	int head=1,tail=1,ans=-INF;q[1]=0;
	for (register int i=1;i<=n;++i)
	{
		while (head<=tail&&q[head]

the end

参考:
https://www.luogu.com.cn/blog/Sweetlemon/dan-diao-dui-lie
https://www.luogu.com.cn/blog/user28920/solution-p1714

你可能感兴趣的:(单调队列)