[JSOI2008] 最大数 (单调栈)

算法#

基础#

发现插入总在最后一个进行

单调栈维护一个区间的 max/min 单调队列维护以一个值为 max/min 的最大区间

显然可以使用单调栈维护
其原理为

a,bseq,a<b,pos[a]<pos[b]
那么显然 a 没有卵用

因此可以用单调栈维护一个包含 seq 的最后一个元素的单调递减序列
求解区间 [L,Last] 的值, 即为求解在 [L,Last] 这一区间内第一个存在于单调栈中的元素

优化#

二分 ( O(nlogn) )#

显然可以二分查找
不加赘述

并查集 (O(n))#

对于一个下标 i 将它和在它之后第一个在单调队列里的数的下标放在同一个并查集中
这样可以保证在插入的过程中仍然可以 O(1) 处理查询

#include <bits/stdc++.h>
const int MAXSIZE = 2e5 + 20;
#define int long long

int M, D;

class Union_Set
{
    private:

    public:
        int fa[MAXSIZE];

        int find(int Point)
        {
            return fa[Point] = (Point == fa[Point]) ? Point : find(fa[Point]);
        }

        void insert(int Fa, int Son)
        {
            fa[find(Son)] = find(Fa);
        }
} US;

struct node
{
    int Val;
    int sub;
};

class MonoStack
{
    private:

    public:
        node Val[MAXSIZE];
        int top;

        void init()
        {
            top = 0;
        }

        void insert(int x, int sub)
        {
            while (Val[top].Val < x && top)
            {
                US.insert(sub, Val[top].sub);
                top--;    
            }
            Val[++top].sub = sub;
            Val[top].Val = x;
        }

} MS;

int t = 0;
int size = 0;
int Num[MAXSIZE];

void solve()
{
    MS.init();
    while(M--)
    {
        char type;
        std::cin >> type;
        if(type == 'A')
        {
            scanf("%lld", &Num[++size]);
            Num[size] = (Num[size] + t) % D;
            US.fa[size] = size; 
            MS.insert(Num[size], size);
        }else{
            int L;
            scanf("%lld", &L);
            L = size - L + 1;
            t = Num[US.find(L)];
            printf("%lld\n", t);
        }
    }
}

signed main()
{
    scanf("%lld %lld", &M, &D);

    solve();

    return 0;
}

总结#

代码#

注意在单调栈弹出是确保位置有意义
并查集插入时需要初始化

思路#

并查集往往可以用来处理连续的链向问题

posted @   Yorg  阅读(6)  评论(0编辑  收藏  举报
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示