Bootstrap

P1198 [JSOI2008] 最大数

P1198 [JSOI2008] 最大数icon-default.png?t=O83Ahttps://www.luogu.com.cn/problem/P1198

牵制芝士:单调队列

思路:

我们的任务是找出一个区间最大值的

因为插入的数与上一次的答案有关 所以它是强制在线的(真无语了

我们可以在每次插入时整一个叫做控制区间的东西

用来表示这个数在这一个连续的区间中是最大值

比如 经过处理后输入数列是3,5,4,1,2

那么它们的控制区间就如下表

序号12345
35412
控制区间1~23~34~5

其中 第1个数会被第2个数“控制”

其中 第4个数会被第5个数“控制”

所以它们的区间被“吞并”了

在查询操作时

我们可以对控制区间进行二分 找出它所对应的值

那如何快速得到控制区间呢?

let us梳理一下过程

首先我们将第1个数存入 

在将第2个数存入 发现它之前的数小于它 就往前冲

将第1个数干掉

看到这 你是不是感觉到不太对劲 这不就是我们熟悉的单调队列吗?

之后便豁然开朗了吧

注:记得取模!

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int m,mod,sum,q[210000],t,cnt,p[210000];
signed main()
{
	scanf("%lld%lld",&m,&mod);
	while(m--)
	{
		char ch;
		int x;
		cin>>ch>>x;
		if(ch=='A')
		{
			x+=sum;
			x%=mod;
			while(t>0&&q[t]<=x)
			{
				t--;
			}
			q[++t]=x;
			p[t]=++cnt;
		}
		else
		{
			int l=1,r=t,st=0;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(p[mid]>=cnt-x+1)
				{
					st=mid;
					r=mid-1;
				}
				else
				{
					l=mid+1;
				}
			}
			sum=q[st];
			printf("%lld\n",q[st]);
		}
	}
	return 0;
}

;