BZOJ 1012 [JSOI2008]最大数maxnumber (单调栈)

来源:互联网 发布:画梁图软件 编辑:程序博客网 时间:2024/06/05 09:49

1012: [JSOI2008]最大数maxnumber

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 11124  Solved: 4868
[Submit][Status][Discuss]

Description

  现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L
个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加
上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取
模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个
数。

Input

  第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来
M行,查询操作或者插入操作。

Output

  对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

Sample Input

5 100
A 96
Q 1
A 97
Q 1
Q 2

Sample Output

96
93
96


线段树可以做,RMQ的模板题,新学到一种处理区间问题的思想,单调栈也可以说是单调队列。维护一个栈,栈内元素入栈先后和元素的大小都是有序的,最后取值的时候只需要二分查找最大数的位置,最后输出即可。

由于后入栈的数如果比先入栈的数大的话,先入栈的数不会输出,所以如果后入栈的数大,就让它直接覆盖掉比它小的数中的最大数,栈中此位置储存当前值在原数组中的下标,因为每次询问都是在上一次L的基础上,所以此题可以用单调队列维护。

其实模拟栈的数组储存的就是原数组的下标,数组中代表原数组元素递减排序,这样可以表示当前最大值可以覆盖后面的较小值,二分查找就是在最后一个较大值前面的大数中,查找符合要求的数的下标,最后输出。

想了两天,自己想通了,可还是不怎么会表达,等以后积淀一下再做总结吧。

注意,cin和cout会RE,我交了差不多20次才A到,这就是玄学的奇妙之处吧。

代码实现:

#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<cstdio>#define ll long long#define mset(a,x) memset(a,x,sizeof(a))using namespace std;const double PI=acos(-1);const int inf=0x3f3f3f3f;const double esp=1e-6;const int maxn=2e5+5;const int mod=1e9+7;int dir[4][2]={0,1,1,0,0,-1,-1,0};ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}ll lcm(ll a,ll b){return a/gcd(a,b)*b;}ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}ll ans[maxn],Stack[maxn];              //Stack单调栈,入栈元素入队先后与数的大小都有序 ,ans储存修改后的值 int main(){char x;int i,j,k,n,d,y,top,len,END;        //END储存后L个数中的最大数,top记录当前最大值在栈中的位置,len记录元素个数 while(scanf("%d %d",&n,&d)){mset(ans,0);mset(Stack,0);END=len=top=0;for(i=1;i<=n;i++){getchar();scanf("%c %d",&x,&y);if(x=='A'){y=(y+END)%d;                             //最大值加上y后取模d ans[++len]=y;                            //y入队列,下标自加 while(top&&ans[Stack[top]]<=y)           //栈不为空,倒序排序 top--; Stack[++top]=len;                        //到当前栈中这个元素对应的原数组的下标 }else{int temp=lower_bound(Stack+1,Stack+top+1,len-y+1)-Stack;    //找到最大值下标的位置 END=ans[Stack[temp]];                                       //输出并记录后L个数的最大值 printf("%d\n",END);  }}}return 0;}


阅读全文
0 0
原创粉丝点击