【Frequent values】题解

\(solution\)

Link

看着题目这么长,其实就是在一个非降序序列中求给定区间中众数所出现的个数。

此题可用莫队来解决。

莫队的模板就不说了,说一下不一样的。

如何求区间众数所出现的个数 :

  • 可以考虑另外开一个桶 \(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;
}
posted @ 2021-03-03 10:51  Ti_Despairy  阅读(99)  评论(1)    收藏  举报