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;
}


目录
相关文章
|
6月前
|
算法 测试技术 C++
【动态规划】【前缀和】【数学】2338. 统计理想数组的数目
【动态规划】【前缀和】【数学】2338. 统计理想数组的数目
|
6月前
|
算法 测试技术 C++
【动态规划】【离线查询】【前缀和】689. 三个无重叠子数组的最大和
【动态规划】【离线查询】【前缀和】689. 三个无重叠子数组的最大和
|
6月前
|
算法 测试技术 C#
区间合并|LeetCode2963:统计好分割方案的数目
区间合并|LeetCode2963:统计好分割方案的数目
|
6月前
|
存储 算法 搜索推荐
【算法训练-排序算法 三】【排序应用】合并区间
【算法训练-排序算法 三】【排序应用】合并区间
81 0
|
12月前
|
人工智能 算法
代码随想录算法训练营第三十五天 | LeetCode 435. 无重叠区间、763. 划分字母区间、56. 合并区间
代码随想录算法训练营第三十五天 | LeetCode 435. 无重叠区间、763. 划分字母区间、56. 合并区间
61 0
|
算法
算法篇之二分查找(第74题探索二维矩阵、第287题寻找重复数)
算法篇之二分查找(第74题探索二维矩阵、第287题寻找重复数)
116 0
|
人工智能 vr&ar
数列分块入门 1 (单点查值,区间加法)
数列分块入门 1 (单点查值,区间加法)
73 0
|
存储
剑指offer 42. 数据流中的中位数
剑指offer 42. 数据流中的中位数
41 0
|
存储 5G 容器
一个很大的文件,存放了10G个整数的乱序数列,如何用程序找出中位数。
一个很大的文件,存放了10G个整数的乱序数列,如何用程序找出中位数。
98 0
|
人工智能
LOJ—— 数列分块入门 2
LOJ—— 数列分块入门 2
85 0