算法
基础
发现插入总在最后一个进行
单调栈维护一个区间的 \(max / min\) 单调队列维护以一个值为 \(max / min\) 的最大区间
显然可以使用单调栈维护
其原理为
当 \(a, b \in seq, a < b, pos[a] < pos[b]\)
那么显然 \(a\) 没有卵用
因此可以用单调栈维护一个包含 \(seq\) 的最后一个元素的单调递减序列
求解区间 \([L, Last]\) 的值, 即为求解在 \([L, Last]\) 这一区间内第一个存在于单调栈中的元素
优化
二分 ( \(O(n\log n)\) )
显然可以二分查找
不加赘述
并查集 (\(O(n)\))
对于一个下标 \(i\) 将它和在它之后第一个在单调队列里的数的下标放在同一个并查集中
这样可以保证在插入的过程中仍然可以 \(O(1)\) 处理查询
#include <bits/stdc++.h>
const int MAXSIZE = 2e5 + 20;
#define int long longint 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;
}
总结
代码
注意在单调栈弹出是确保位置有意义
并查集插入时需要初始化
思路
并查集往往可以用来处理连续的链向问题