BZOJ 1012 [JSOI2008]最大数maxnumber

怎么做都可以题。。可以用线段树。。可以用平衡树。。反正有不少方法

个人比较滋磁单调队列+二分查找的写法,常数小代码少易理解。

具体思路就是维护一个单调不上升的单调队列,然后查询就在这个单调队列中二分查找就好啦~

 

//这道题,可以算是单调队列的一个妙用了
//当然,做法有很多,可以用线段树、平衡树、树状数组等,其中单调队列最巧妙且最简单

//为什么这道题可以使用单调队列呢?
//(即队列中存储的序列必定是下标单调并且数值单调) 
//如果每个结点没有下标优势(早点入队)也没有数值优势(更大),那么显然无论如何都不能作为答案
//然后如何查询呢?
//显然,使用顺序查找必定是会超时的
//注意到下标单调,满足可以使用二分答案的条件。我们可以使用二分答案来找到查询的位置
//(在满足 该节点的下标>=查询的最左边的下标 的前提下下标最小的元素) 

#include <deque>
#include <cstdio>

using namespace std;

struct node
{
    node(const size_t &a = 0, const int &b = 0) : Number(a), Value(b) {}
    size_t Number;
    int Value;
};

unsigned int M;
int D;

size_t Len;
deque<node> S;

int t;

int Search(const size_t &Left)
{
    size_t l(0), r(S.size()), mid;
    
    while (l < r)
    {
        mid = l + ((r - l) >> 1);
        if (S[mid].Number >= Left)
            r = mid;
        else
            l = mid + 1;
    }
    
    return S[l].Value;
}

int main()
{
    char op[10];
    int Input;
    
    scanf("%u%d", &M, &D);
    while (M--)
    {
        scanf("%s%d", op, &Input);
        
        if (*op == 'A')
        {
            Input += t;
            Input %= D;
            while (S.empty() == false && S.back().Value < Input)
                S.pop_back();
            S.push_back(node(++Len, Input));
        }
        else
            printf("%d\n", t = (S.empty() ? 0 : Search(Len - Input + 1)));
    }
    
    return 0;
}
BZOJ 1012

 

你可能感兴趣的:(BZOJ 1012 [JSOI2008]最大数maxnumber)