【JSOI2008】最大数 Max Number

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 表反过来
那么在最后添加数的操作不必影响到之前的结果

原文地址:https://www.cnblogs.com/ccryolitecc/p/13819756.html