bzoj 1012: [JSOI2008]最大数maxnumber(单调栈新用法+二分)

题目链接

1012: [JSOI2008]最大数maxnumber

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 10416  Solved: 4558
[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

HINT

 

  数据如下http://pan.baidu.com/s/1i4JxCH3

 

题解:

初看,一定以为是个线段树的题,是的,这个题线段树可以过,下面将另一种写法:

这题可以用单调栈+二分做,维护一个单调递减的单调栈,与以往不同的是,此处单调栈中存的是元素在数组中的位置而不是值的大小,那么查询时只要在单调栈中查询比num-l+1大的元素。(num为当前数组中元素总数,l为查询长度)。

详见代码:

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=2e5+100;
ll s[maxn],a[maxn];
int top=0;
int main()
{
    int m;
    ll d;
    scanf("%d%lld",&m,&d);
    ll t=0;
    int num=0;
    while(m--)
    {
        char ss[10];
        scanf("%s",ss);
        if(ss[0]=='A')
        {
            ll v;
            scanf("%lld",&v);
            v=(v+t)%d;
            a[++num]=v;
            while(top&&a[s[top]]<=v) top--;
            s[++top]=num;
        }
        else if(ss[0]=='Q')
        {
            int l;
            scanf("%d",&l);
            int p=lower_bound(s+1,s+top+1,num-l+1)-s;
            t=a[s[p]];
            printf("%lld\n",t);
        }
    }
    return 0;
}

 

 

 

 

posted @ 2017-07-12 20:47  tarjan's  阅读(107)  评论(0编辑  收藏  举报