题意: 给定一个长度为
n
n
n的序列,和
q
q
q个询问,求每个询问
[
l
,
r
]
[l,r]
[l,r]中最大的
h
h
h,满足该区间内至少有
h
h
h个数的值大于
h
h
h。
思路: 二分
h
h
h,求比
h
h
h大的数的个数。也可以二分后求区间第
m
m
m小的数与
m
m
m比较。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5 + 10;
int n, q, a[N], root[N], cnt;
struct node {
int l, r, num;
} zxs[N * 40];
void add(int l, int r, int pre, int &now, int pos) {
zxs[++cnt] = zxs[pre], now = cnt, zxs[cnt].num++;
if(l == r)
return;
int m = (l + r) >> 1;
if(pos <= m)
add(l, m, zxs[pre].l, zxs[cnt].l, pos);
else
add(m + 1, r, zxs[pre].r, zxs[cnt].r, pos);
}
int query(int k, int l, int r, int L, int R) {//求比k小的数的个数
if(k > r)
return zxs[R].num - zxs[L].num;
int m = (l + r) >> 1, ans = 0;
if(k > l)
ans += query(k, l, m, zxs[L].l, zxs[R].l);
if(k > m + 1)
ans += query(k, m + 1, r, zxs[L].r, zxs[R].r);
return ans;
}
int main() {
while(~scanf("%d%d", &n, &q)) {
cnt = 0;
memset(root, 0, sizeof root);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
add(1, n, root[i - 1], root[i], a[i]);
}
for(int x, y, i = 1; i <= q; i++) {
scanf("%d%d", &x, &y);
int h, l = 1, r = n;
while(l < r) {
h = (l + r + 1) >> 1;
if(((y - x + 1) - query(h, 1, n, root[x - 1], root[y])) >= h)
l = h;
else
r = h - 1;
}
printf("%d\n", l);
}
}
return 0;
}