P1198 [JSOI2008]最大数
题目描述
现在请求你维护一个数列,要求提供以下两种操作:
1、 查询操作。
语法:Q L
功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。
限制: LLL 不超过当前数列的长度。 (L>0)(L > 0)(L>0)
2、 插入操作。
语法:A n
功能:将 nnn 加上 ttt ,其中 ttt 是最近一次查询操作的答案(如果还未执行过查询操作,则 t=0t=0t=0 ),并将所得结果对一个固定的常数 DDD 取模,将所得答案插入到数列的末尾。
限制: nnn 是整数(可能为负数)并且在长整范围内。
注意:初始时数列是空的,没有一个数。
输入输出格式
输入格式:
第一行两个整数, MMM 和 DDD ,其中 MMM 表示操作的个数 (M≤200,000)(M \le 200,000)(M≤200,000) , DDD 如上文中所述,满足 (0
接下来的 MMM 行,每行一个字符串,描述一个具体的操作。语法如上文所述。
输出格式:
对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。
输入输出样例
输入样例#1: 复制
5 100
A 96
Q 1
A 97
Q 1
Q 2
输出样例#1: 复制
96
93
96
单调栈 + 二分查找做法
#include
using namespace std;
typedef long long LL;
typedef pair P;
const int maxn = 2e5 + 1000;
int cnt[maxn];
int a[maxn];
int m;
int d;
int tail;
int main()
{
scanf("%d%d",&m,&d);
int t = 0;
int num = 0;
tail = -1;
while(m--)
{
char op;
cin >> op;
if(op == 'A')
{
int n;
scanf("%d",&n);
n = (n+t)%d;
while(tail >= 0 && a[cnt[tail]] < n) tail--;
a[++num] = n;
cnt[++tail] = num;
}
else {
int L;
scanf("%d",&L);
//printf("0\n");
L = (num-L+1);
int idx = lower_bound(cnt,cnt+tail+1,L) - cnt;
printf("%d\n",a[cnt[idx]]);
t = a[cnt[idx]];
}
}
return 0;
}
单调栈 + 并查集做法
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
ST表做法,反向建ST表,f[i][j] 表示 a[i-(1< a[i] 的最大值 ,因为前面的值不会改变,所以就相当于一个不断建表的过程。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
反向树状数组
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
线段树 单点更新+区间求最值
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include