严格次大值 一道数列分块入门题 题解
题目描述
给你一个长度为 \(n\) 的数列 \(a_1, a_2, \ldots, a_n\)。
接下来有 \(q\) 次操作,操作分为如下两种类型:
- \(\mathtt{1\ l\ r\ x}\):将下标在 \([l, r]\) 范围内的每个数(即 \(a_l, a_{l+1}, \ldots, a_r\))的数值各增加 \(x\);
- \(\mathtt{2\ l\ r}\):查询下标在 \([l, r]\) 范围内的所有数值中的严格次大值,即查询 \(a_l, a_{l+1}, \ldots, a_r\) 中比 \(\max\limits_{l \le i \le r} \{ a_i \}\) 小的数里面最大的那个数的数值。特别地,如果不存在严格次大值(即 \(a_l = a_{l+1} = \ldots = a_r\)),输出 \(-1\)。
你需要依次执行上述操作,并且对于每个查询操作,输出对应的结果。
输入格式
第一行,一个整数 \(n\),表示数列长度。
第二行,\(n\) 个整数 \(a_1, a_2, \ldots, a_n\),表示初始时数列中每个元素的数值。
第三行,一个整数 \(q\),表示操作次数。
接下来 \(q\) 行,每行包含一个操作(\(1\ l\ r\ x\) 或 \(2\ l\ r\))。
输出格式
对于每次查询操作(\(2\ l\ r\)),输出一行,包含一个整数,表示数列 \(a\) 中第 \(l\) 个数到第 \(r\) 个数的严格次大值。
样例
样例输入1
5
1 2 3 4 5
6
2 2 3
1 1 2 1
2 2 3
1 3 5 2
1 1 2 7
2 1 5
样例输出1
2
-1
9
样例输入2
10
2 3 3 2 3 3 2 3 3 2
9
2 2 3
1 1 3 2
1 3 7 3
2 1 5
1 4 9 6
1 5 10 2
1 7 9 3
2 1 8
2 4 10
样例输出2
-1
6
14
14
说明/提示
数据规模与约定
- 对于 \(50\%\) 的数据,\(n, q \le 1000\)
- 对于 \(100\%\) 的数据,\(2 \le n \le 10^5, 1 \le q \le 10^5\),\(1 \le a_i, x \le 1000\),\(1 \le l \lt r \le n\)
题解
- \(id_i\) 表示 \(a_i\) 所在的分块编号
- \(d_i\) 表示第 \(i\) 个分块的整体增量;
- \(m1_i\) 表示第 \(i\) 个分块的最大值(不考虑整体增量 \(d_i\))
- \(m2_i\) 表示第 \(i\) 个分块的严格次大值(不考虑整理增量 \(d_i\)),如果这个分块没有严格次大值(即所有数都一样)则 \(m2_i = 0\)
然后你就会发现这是一道 数列分块 的入门模板题。
示例程序如下(代码有啥不懂的地方可以在下方留言):
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, blo, q, d[400], m1[400], m2[400], a[maxn], id[maxn];
void update(int p) {
m1[p] = m2[p] = 0;
for (int i = (p-1)*blo+1; i <= min(n, p*blo); i++)
m1[p] = max(m1[p], a[i]);
for (int i = (p-1)*blo+1; i <= min(n, p*blo); i++)
if (a[i] != m1[p])
m2[p] = max(m2[p], a[i]);
}
void add(int l, int r, int x) {
if (id[l] + 1 >= id[r]) {
for (int i = l; i <= r; i++)
a[i] += x;
update(id[l]);
if (id[l] < id[r])
update(id[r]);
}
else {
for (int i = l; i <= id[l]*blo; i++)
a[i] += x;
update(id[l]);
for (int i = (id[r]-1)*blo+1; i <= r; i++)
a[i] += x;
update(id[r]);
for (int i = id[l]+1; i < id[r]; i++)
d[i] += x;
}
}
void f(int c, int &a, int &b) {
if (c > a) {
b = a;
a = c;
}
else if (c < a && c > b)
b = c;
}
int query(int l, int r) {
int max1 = -1, max2 = -1;
if (id[l] + 1 >= id[r]) {
for (int i = l; i <= r; i++)
f(a[i] + d[id[i]], max1, max2);
}
else {
for (int i = l; i <= id[l]*blo; i++)
f(a[i] + d[id[i]], max1, max2);
for (int i = (id[r]-1)*blo+1; i <= r; i++)
f(a[i] + d[id[i]], max1, max2);
for (int i = id[l]+1; i < id[r]; i++) {
f(m1[i] + d[i], max1, max2);
if (m2[i])
f(m2[i] + d[i], max1, max2);
}
}
return max2;
}
int main() {
scanf("%d", &n);
blo = sqrt(n);
for (int i = 1; i <= n; i++) {
scanf("%d", a+i);
id[i] = (i - 1) / blo + 1;
}
for (int i = 1; i <= id[n]; i++)
update(i);
scanf("%d", &q);
while (q--) {
int op, l, r, x;
scanf("%d%d%d", &op, &l, &r);
if (op == 1) {
scanf("%d", &x);
add(l, r, x);
}
else
printf("%d\n", query(l, r));
}
return 0;
}
浙公网安备 33010602011771号