CSU-2221 假装是区间众数(ST表模版题)
Posted artoriax
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSU-2221 假装是区间众数(ST表模版题)相关的知识,希望对你有一定的参考价值。
题目链接
题目
Description
给定一个非递减数列Ai,你只需要支持一个操作:求一段区间内出现最多的数字的出现次数。
Input
第一行两个整数N,Q
接下来一行有N个整数,表示这个序列。
接下来Q行每行一个操作:A B,询问A到B之间出现最多的数字。
1<=N,Q<=100000。-100000<=Ai<=100000
Output
每组数据若干行,每行对应一个询问的答案。
Sample Input
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
Sample Output
1
4
3
题解
这个题是ST表+RMQ模版题
首先题中所给序列是非递减序列,所有相等的数都会聚在一块,所以我们可以将相等的数字划为一段,(value[i]和cnt[i])分别表示第i段对应的数值和出现的次数,(num[p],L[p],R[p])分别表示位置p所在段的编号和左右端点的位置,每次查询(l, r)的结果分为三部分的最大值,从(l到l)所在段的右端点的元素个数((R[l]-l+1)),从r所在段的左端点到r的元素个数((r-L[r]+1)),中间第(num[l]+1段到num[r]-1)段cnt的最大值,这样就可以用rmq解决了。
顺便复习一下ST+RMQ
时间复杂度:预处理(o(nlogn)),查询(o(1))
(st[i][j])表示从i开始,长度为(2^j)的一段元素中的最小(大)值,则可以用递推的方式计算(st[i][j])
[st[i][j]=min(st[i][j-1],st[i+2^{j-1}][j-1])]
循环的时候注意先枚举区间长度,即先枚举j,再枚举起点i,从小区间到大区间。
查询也很简单,查询(L,R)区间内的最小(大)值,直接令x为满足(2^x le R-L+1)的最大整数,则以L开头,R结尾的两个长度为(2^x)的区间覆盖了(L,R),由于是取最小值,所以有些元素考虑多遍也没关系,故ST表不能用于区间和
AC代码
#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int a[maxn];
int value[maxn], cnt[maxn], num[maxn], L[maxn], R[maxn];
int st[maxn][20], lg2[maxn];
int n, q;
int k;
void ST() {
for (int i = 1; i <= k; i++) {
st[i][0] = cnt[i];
}
for (int j = 1; (1 << j) <= k; j++) {
for (int i = 1; (i + (1 << j) - 1) <= k; i++) {
st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
for (int i = 2; i <= k; i++) {
lg2[i] = lg2[i >> 1] + 1;
}
}
int rmq(int l, int r) {
if (l>r)
return 0;
else {
int x = lg2[r - l + 1];
return max(st[l][x], st[r - (1 << x) + 1][x]);
}
}
int main() {
scanf("%d%d", &n, &q);
k = 0;
value[0] = 0x3f3f3f3f;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] != value[k]) {
R[k] = i;
value[++k] = a[i];
L[k] = i - 1;
cnt[k] = 1;
num[i] = k;
}
else {
cnt[k]++;
num[i] = num[i - 1];
}
}
R[k] = n + 1;
ST();
while (q--) {
int l, r;
scanf("%d%d", &l, &r);
if (num[l] == num[r]) {
printf("%d
", r - l + 1);
}
else {
int tmp = max(R[num[l]] - l, r - L[num[r]]);
int ans = max(tmp, rmq(num[l] + 1, num[r] - 1));
printf("%d
", ans);
}
}
return 0;
}
/**********************************************************************
Problem: 2221
User: Artoriax
Language: C++
Result: AC
Time:128 ms
Memory:12572 kb
**********************************************************************/
以上是关于CSU-2221 假装是区间众数(ST表模版题)的主要内容,如果未能解决你的问题,请参考以下文章