Step1 Problem:
给你 n 个数分别为 a[1], a[2], … a[n],m 个询问。
对于每个询问:
询问区间 L 到 R:有 k 个不同的元素 满足 它们都出现了 k 次,我们要输出最大的 k。
Step2 Ideas:
vis[i]:维护区间 i 这个元素出现几次。
sum[i]:出现次数大于 i 次的不同元素个数。
如果新增一个元素:vis[i] 加 1,发生改变 sum[vis[i]] 加 1 了,这个改变可能使得答案变大。
如果减少一个元素:发生改变 sum[vis[i]] 减 1 了,这个改变可能使得答案变小,vis[i] 减 1.
注意 vis[i] 的顺序。
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 3e4+5;
struct node
{
int l, r, id;
}Q[N];
int a[N], ls[N], la[N], pos[N];
bool cmp(node x, node y)
{
if(pos[x.l] == pos[y.l]) return x.r < y.r;
return pos[x.l] < pos[y.l];
}
int vis[N], sum[N], ans[N];
int L, R, Ans;
void add(int x)
{
vis[la[x]]++;
sum[vis[la[x]]]++;
if(min(sum[vis[la[x]]], vis[la[x]]) > Ans) Ans = min(sum[vis[la[x]]], vis[la[x]]);
}
void del(int x)
{
sum[vis[la[x]]]--;
if(vis[la[x]] == Ans && sum[vis[la[x]]] < Ans) {
Ans = sum[vis[la[x]]];
}
vis[la[x]]--;
}
int main()
{
int n, q;
scanf("%d %d", &n, &q);
int cnt = 0;
int block = sqrt(n);
for(int i = 1; i <= n; i++)
{
scanf("%d", a+i);
ls[cnt++] = a[i];
pos[i] = i/block;
}
sort(ls, ls+cnt);
cnt = unique(ls, ls+cnt) - ls;
for(int i = 1; i <= n; i++)
la[i] = lower_bound(ls, ls+cnt, a[i]) - ls + 1;
for(int i = 1; i <= q; i++)
scanf("%d %d", &Q[i].l, &Q[i].r), Q[i].id = i;
sort(Q+1, Q+1+q, cmp);
L = 1, R = Ans = 0;
for(int i = 1; i <= q; i++)
{
while(L < Q[i].l)
del(L), L++;
while(L > Q[i].l)
add(L-1), L--;
while(R < Q[i].r)
add(R+1), R++;
while(R > Q[i].r)
del(R), R--;
ans[Q[i].id] = Ans;
}
for(int i = 1; i <= q; i++)
printf("%d\n", ans[i]);
return 0;
}