Link:
Luogu: https://www.luogu.com.cn/problem/P1198
Solution 1
要求支持:在数列末尾插入一个数 以及 查询数列末尾 (L) 个数中的最大值
并不是移动窗口,所以单调队列或者单调栈做不了。
还有什么方法呢?很明显,可以开一个可持久化线段树……
……也可以就开一个权值线段树,记录一下每个线段树结点被最后访问的时间
引导查询时的移动路径。
不过仔细一看这题强制在线就没法离散化辣
那怎么办呢
假如按照位置而不按照权值呢?
这样的话,单次查询复杂度 (O(log^2n))
完毕
①线段树忘记空间开大了
②这树一开始就得开满。一不小心顺手打了个insert(1, 1, n)
Code 1
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN = 2e5 + 10;
int n, m;
long long D;
int tot = 0;
int lc[MAXN<<2], rc[MAXN<<2];
long long mxx[MAXN<<2];
int root = 0;
long long qmax(int &pos, int l, int r, int ql, int qr)
{
if (!pos) pos = ++tot;
if (ql > r || qr < l) return 0;
if (ql <= l && qr >= r) return mxx[pos];
int mid = l + r >> 1;
return max(qmax(lc[pos], l, mid, ql, qr), qmax(rc[pos], mid+1, r, ql, qr));
}
void ins(int &pos, int l, int r, int id, int val)
{
if (!pos) pos = ++tot;
if (l == r)
{
mxx[pos] = val;
return;
}
int mid = l + r >> 1;
if (id <= mid) ins(lc[pos], l, mid, id, val);
else ins(rc[pos], mid+1, r, id, val);
mxx[pos] = max(mxx[lc[pos]], mxx[rc[pos]]);
}
int main()
{
cin >> m >> D;
char ch;
long long NNN = 0, TTT = 0;
for (int k, i = 1; i <= m; ++i)
{
cin >> ch;
if (ch == 'Q')
{
cin >> k;
TTT = qmax(root, 1, m, n-k+1, n);
cout << TTT << endl;
}
else
{
cin >> NNN;
++n;
NNN = ( (NNN+TTT)%D );
ins(root, 1, m, n, NNN);
}
}
return 0;
}
Solution 2
把 ST 表反过来
那么在最后添加数的操作不必影响到之前的结果