【Frequent values】题解
【\(solution\)】
看着题目这么长,其实就是在一个非降序序列中求给定区间中众数所出现的个数。
此题可用莫队来解决。
莫队的模板就不说了,说一下不一样的。
如何求区间众数所出现的个数 :
- 可以考虑另外开一个桶 \(tmp\) 表示出现次数为 \(x\) 的数的个数。
- 对于每次的 \(add\) ,可以先把 \(tmp[x] - 1\) ,再把 \(tmp[x + 1] + 1\)
- 对于每次的 \(del\) ,可以先把 \(tmp[x] - 1\) ,再把 \(tmp[x - 1] + 1\)
- 再用一个 \(sum\) 统计答案即可。
注意 :
用 \(cnt[x]\) 表示数值为 \(x\) 的数的个数。
-
\(add\) 没有什么问题,每次 \(sum\) 和 \(cnt[x + 1]\) 取一遍最大值即可。
-
\(del\) 时要判断 \(cnt[x] = sum\) 和 \(tmp[cnt[x]] = 0\) ,如果两个条件都满足,就表示众数的个数少了一个,\(sum - 1\) 即可。
仅满足 \(cnt[x] = sum\) ,就表示这是另为一个众数。
仅满足 \(tmp[cnt[x]] = 0\) ,表示不是众数的数的个数减少了,对答案无影响。
这里是因为莫队是一个一个数判断,所以 \(sum - 1\) 就可以代表减少后众数的数量。
小细节
- 因为数字有负的,所以直接加上 \(10 ^ 5\) 就可以把所有的数值变为正的,因为是求众数,所以不会对答案产生影响。
- 如果你很闲,你也可以写一个离散化来维护。
- 建议莫队的初始化 \(l = 1\) ,\(r = 0\) , \(l = 0\) 时有时会 \(RE\) 。
- 多组数据记着清空。
【\(Code\)】
贴一发离散化的
#include <bits/stdc++.h>
using namespace std;
const int M = 1e5 + 10;
int n,m,block;
int a[M],ans[M],sum,cnt[M],tmp[M],last[M],b[M];
struct node{
int l;
int r;
int pos;
}s[M];
inline int read()
{
int s = 0, f = 0;char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
inline bool CMP(node a,node b)
{
return (a.l / block) ^ (b.l / block) ? a.l < b.l : ( ( (a.l / block) & 1) ? a.r < b.r : a.r > b.r);
}
void add(int x)
{
tmp[cnt[a[x]]]--;
tmp[++cnt[a[x]]]++;
sum = max(sum,cnt[a[x]]);
return;
}
void del(int x)
{
tmp[cnt[a[x]]]--;
if(cnt[a[x]] == sum && tmp[cnt[a[x]]] == 0) sum --;
tmp[--cnt[a[x]]]++;
return;
}
void clear()
{
memset(tmp,0,sizeof tmp);
memset(cnt,0,sizeof cnt);
memset(ans,0,sizeof ans);
memset(b,0,sizeof b);
for(int i = 1;i <= m;i ++) {
s[i].l = 0;
s[i].r = 0;
s[i].pos = 0;
}
sum = 0;
return;
}
signed main()
{
while(1) {
clear();
n = read();
if(!n) break;
m = read();
for(int i = 1;i <= n;i ++) a[i] = read(),b[i] = a[i];
int tot = unique(b + 1,b + n + 1) - b - 1;
for(int i = 1;i <= n;i ++) a[i] = lower_bound(b + 1,b + 1 + tot,a[i]) - b;
block = pow(n,0.6666667);
for(int i = 1;i <= m;i ++) {
s[i].l = read();
s[i].r = read();
s[i].pos = i;
}
sort(s + 1,s + m + 1,CMP);
int l = 1,r = 0;
for(int i = 1;i <= m;i ++) {
int ql = s[i].l;
int qr = s[i].r;
while(l < ql) del(l ++);
while(l > ql) add(-- l);
while(r > qr) del(r --);
while(r < qr) add(++ r);
ans[s[i].pos] = sum;
}
for(int i = 1;i <= m;i ++) printf("%d\n",ans[i]);
}
return 0;
}