题目大意
给出一个长度为
n
n
n的数列
a
1
,
a
1
,
⋯
,
a
n
a_1,a_1,\cdots,a_n
a1,a1,⋯,an
有
q
q
q次询问,
每次询问给出
l
,
r
,
k
l,r,k
l,r,k,询问区间
[
l
,
r
]
[l,r]
[l,r]中出现次数严格大于
r
−
l
+
1
k
\frac{r-l+1}{k}
kr−l+1的最小的数是多少。
如果不存在满足题意的数,就输出-1
。
时间限制
2.5s
数据范围
n
,
q
≤
3
×
1
0
5
n,q\le 3\times 10^5
n,q≤3×105
a
i
≤
n
a_i\le n
ai≤n
2
≤
k
≤
5
2\le k \le 5
2≤k≤5
题解
静态数组,询问区间数的个数,很显然就是主席树。
因为
k
k
k最大只有5,因此在树上查询的时候,最多只会有
5
5
5条分支。
因此时间复杂度没有任何问题。
只要动态开节点,基本上空间也没有任何问题。
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#define G getchar
#define ll long long
using namespace std;
int read()
{
char ch;
for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
int n = 0 , w;
if (ch == '-')
{
w = -1;
ch = G();
} else w = 1;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const int N = 300005;
int s[N * 40] , ls[N * 40] , rs[N * 40];
int opl , opr , ops , opx;
int n , tmp , root[N];
int tot , l , r , k , m;
void ins(int xx , int x , int l , int r)
{
if (l == r)
{
s[x] = s[xx] + 1;
return;
}
int mid = (l + r) / 2;
if (mid < opr)
{
tot++;
rs[x] = tot;
ls[x] = ls[xx];
ins(rs[xx] , rs[x] , mid + 1 , r);
}
else
{
tot ++;
rs[x] = rs[xx];
ls[x] = tot;
ins(ls[xx] , ls[x] , l , mid);
}
s[x] = s[ls[x]] + s[rs[x]];
}
void find(int xx , int x , int l , int r)
{
if (s[x] - s[xx] < ops || opx != -1) return;
if (l == r)
{
opx = l;
return;
}
int mid = (l + r) / 2;
find(ls[xx] , ls[x] , l , mid);
find(rs[xx] , rs[x] , mid + 1 , r);
}
int main()
{
//freopen("d.in","r",stdin);
//freopen("d.out","w",stdout);
n = read();
m = read();
for (int i = 1 ; i <= n ; i++)
{
tot++;
root[i] = tot;
tmp = read();
opl = opr = tmp;
ins(root[i - 1] , root [i] , 1 , n);
}
for (int i = 1 ; i <= m ; i++)
{
l = read();
r = read();
k = read();
ops = (r - l + 1) / k + 1;
opx = -1;
find(root[l - 1] , root[r] , 1 , n);
printf("%d\n", opx);
}
return 0;
}