LOJ6285.数列分块入门 9(分块在线求区间众数)

简介: LOJ6285.数列分块入门 9(分块在线求区间众数)

link

思路:

考虑对于查询的区间来说众数出现的几种可能:


左端点q l所在块的数

右端点q r所在块的数

b e l o n g [ q l ] + 1 到 b e l o n g [ q r ] − 1的块的众数

对于每一种可能,我们都计算出他出现的次数,最后取出现次数最多并且值最小的就可以。

如何求某个数在某段区间的出现次数呢?大概有两种做法,一是前缀和,二是二分;对于每一个数都用v e c t o r存储一下他出现过的位置,每次用u p p e r _ b o u n d − l o w e r _ b o u n d就是答案。

由于a i的范围过大,所以需要离散化一波~

对于前两种可能,我们可以直接枚举出现的每个数,复杂度为O ( 2 n );

第三种可能,直接枚举显然不现实。预处理出d p [ i ] [ j ]表示第i块到第j块的众数。

for(int i=1;i<=num;i++){
    int res=0,cnt=0;
    memset(mp,0,sizeof mp);
    for(int j=(i-1)*block+1;j<=n;j++){
      mp[a[j]]++;
      if(mp[a[j]]>cnt) cnt=mp[a[j]],res=a[j];
      else if(mp[a[j]]==cnt&&a[j]<res) res=a[j];
      dp[i][belong[j]]=res;
    }
  }

枚举i表示起始块的编号,j表示后面的数,递推过去就好了。时间复杂度为O ( n n )

对于查询的时候,枚举每一个可能的数并且计算出现的次数,取最大值就好了。

要注意,离散化后的下标关系,容易搞混。

代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PLL;
typedef pair<int, int>PII;
typedef pair<double, double>PDD;
#define I_int ll
inline ll read(){ll x = 0, f = 1;char ch = getchar();while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;}
inline void write(ll x){if (x < 0) x = ~x + 1, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');}
#define read read()
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
ll ksm(ll a, ll b,ll mod){ll res = 1;while(b){if(b&1)res=res*a%mod;a=a*a%mod;b>>=1;}return res;}
const int maxn=100000+7,maxm=2e5+7,inf=0x3f3f3f3f;
int a[maxn],b[maxn],n,block,m,l[5100],r[5100],belong[maxn];
vector<int>g[maxn];
int dp[5100][5100],mp[maxn];
int Find(int x, int l, int r) {
    return upper_bound(g[x].begin(), g[x].end(), r) - lower_bound(g[x].begin(), g[x].end(), l);
}
int query(int ql,int qr){
  int res=inf,cnt=0;
  if(belong[ql]==belong[qr]){
    rep(i,ql,qr){
      int tmp=Find(a[i],ql,qr);
      if(cnt<tmp) cnt=tmp,res=a[i];
      else if(cnt==tmp&&a[i]<res) res=a[i];
    }
    return res;
  }
  res=dp[belong[ql]+1][belong[qr]-1];
  cnt=Find(res,ql,qr);
  rep(i,ql,r[belong[ql]]){
    int tmp=Find(a[i],ql,qr);
    if(cnt<tmp) cnt=tmp,res=a[i];
    else if(cnt==tmp&&a[i]<res) res=a[i];
  }
  rep(i,l[belong[qr]],qr){
    int tmp=Find(a[i],ql,qr);
    if(cnt<tmp) cnt=tmp,res=a[i];
    else if(cnt==tmp&&a[i]<res) res=a[i];
  }
  return res;
}
int main(){
  n=read;
  block=150;
  int num=n/block;
  if(n%block) num++;
  rep(i,1,num) l[i]=(i-1)*block+1,r[i]=i*block;
  rep(i,1,n) a[i]=read,b[i]=a[i];
  sort(b+1,b+1+n);
  m=unique(b+1,b+1+n)-(b);
  rep(i,1,n){
    a[i]=lower_bound(b+1,b+m,a[i])-(b);
    g[a[i]].push_back(i);
    belong[i]=(i-1)/block+1;
  }
  for(int i=1;i<=num;i++){
    int res=0,cnt=0;
    memset(mp,0,sizeof mp);
    for(int j=(i-1)*block+1;j<=n;j++){
      mp[a[j]]++;
      if(mp[a[j]]>cnt) cnt=mp[a[j]],res=a[j];
      else if(mp[a[j]]==cnt&&a[j]<res) res=a[j];
      dp[i][belong[j]]=res;
    }
  }
  rep(i,1,n){
    int ql=read,qr=read;
    write(b[query(ql,qr)]);
    puts("");
  }
  return 0;
}


目录
相关文章
|
人工智能 vr&ar
数列分块入门 1 (单点查值,区间加法)
数列分块入门 1 (单点查值,区间加法)
90 0
loj数列分块入门(上)
数列分块入门 入门 1-区间加法-单点查询 入门 2-区间加法-区间查询 入门 3-区间加法-单点查询 入门 4-区间加法-区间查询 入门 5-区间开方-区间查询
107 0
loj数列分块入门(上)
|
人工智能 vr&ar
LOJ——数列分块入门1
LOJ——数列分块入门1
104 0
|
人工智能
LOJ—— 数列分块入门 2
LOJ—— 数列分块入门 2
96 0
loj数列分块入门(下)
入门 6-单点插入-单点查询 入门 7-区间乘法-区间加法-单点查询 入门 8-区间修改-区间查询 入门 9-区间查询众数
114 0
loj数列分块入门(下)
|
算法
算法篇之二分查找(第74题探索二维矩阵、第287题寻找重复数)
算法篇之二分查找(第74题探索二维矩阵、第287题寻找重复数)
131 0
|
存储 人工智能 算法
【前缀和】截断数组、K倍区间、激光炸弹
现在,要将该数组从中间截断,得到三个非空子数组。
96 0
|
算法 C语言
[较难]LeetCode-4.寻找两个正序数组的中位数 利用数组扩充和二分法切割思想实现
题目 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。 请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 你可以假设 nums1 和 nums2 不会同时为空。 示例 : nums1 = [1, 3] nums2 = [2] 则中位数是 2.0
276 0
|
存储
使用最小堆解决海量数据数据中求TopK最大的几个数问题
前几天面试遇到了这么一个问题: 求一亿个数据中最大的100个数. 这个问题一脸懵逼我.后来查了资料说使用HASH函数以及分治的思想来解决.将这1亿个数根据HASH去重然后根据hash值分别存储到1000个分区内,然后每个分区都使用一个容量为100的最小堆得到每个区最大的100个数.
1703 0

热门文章

最新文章