题目链接:1012: [JSOI2008]最大数maxnumber
题意
中文题,点链接看吧,就不copy了。
思路
打眼一看立刻就想到线段树,但本题的区间最值查找每次都是在查后L位,感觉用线段树有些大材小用了。
再仔细想想,发现,如果倒数第i个比倒数第i+1个数小,那么第i个数是没有用的,任意查询的最值都不会是它,因为查的是后L个嘛。
所以呢,我们我以维护一个栈,每次添加新元素时,将其与栈顶元素比较,若栈顶元素小,即无用了,那就出栈,否则,就将新元素入栈。
在查询时直接对栈里元素进行二分查找就好了,假如我们要查询后L位的最值,那么区间第一个数是d[len-L]。
我们只需找出栈中大于等于len-L的最小值,这个值就是区间最值的下标。(栈里当然存下标,要不然何谈二分)
代码
#include <iostream>
#include <cstring>
#include <math.h>
#include <cstdio>
#include <stack>
using namespace std;
const int N = 99999;
int d[N];
int sk[N];
int main()
{
char s[2];
int x, n, mod, t, len=0, a=0;
scanf("%d%d", &n, &mod);
int st = 0;
while(n--)
{
scanf("%s%d", s, &x);
if(s[0] == 'A')
{
d[len] = (x+a)%mod;
while(st > 0)
{
int temp = sk[st];
if(d[temp] > d[len])
break;
st--;
}
sk[++st] = len;
len++;
}
else
{
int z = len-x;
int l = 1;
int r = st;
while(l < r)
{
int mid = (l+r)>>1;
if(sk[mid] < z)
l = mid+1;
else
r = mid;
}
a = d[sk[r]];
printf("%d\n", d[sk[r]]);
}
}
return 0;
}