思路:
考虑对于查询的区间来说众数出现的几种可能:
左端点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; }