P3709 大爷的字符串题
P3709 大爷的字符串题
题目翻译:
这道题充分的体现了信竞对语文的要求之高,读一个小时也读不懂 给出一个长度为 \(n\) 的序列,\(m\) 次询问,求区间 \([l,r]\) 间的众数的个数。
思路:
又是求区间值,考虑莫队。发现我们只需要用莫队来维护区间内每一种数的个数,然后找到数量最多的一个即为答案。
如何删减点?\(cnt[i]\) 表示第 \(i\) 个数出现了几次 ,\(t[i]\) 表示出现 \(i\) 次的数有几个。那增加点的时候,直接判断取较大值,删点时要判断是否为出现次数最多的数,若是则要将答案减一
int Ans;
void add(int i){
t[cnt[i]]--;
t[++cnt[i]]++;
Ans=max(Ans,cnt[i]);
}
void del(int i){
t[cnt[i]]--;
if(cnt[i]==Ans && !t[cnt[i]])Ans--;
t[--cnt[i]]++;
}
由于本题的 \(a[i]\)较大则需要离散化一下。否则会 \(RE\)
完整代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N],cnt[N],b[N],d[N];
struct query{
int l,r,id,k;
}q[N];
int ans[N];
int t[N];
bool cmp(query x,query y){
if(x.k!=y.k){
return x.k<y.k;
}
else if(x.k&1){
return x.r<y.r;
}
else{
return x.r>y.r;
}
}
int Ans;
void add(int i){
t[cnt[i]]--;
t[++cnt[i]]++;
Ans=max(Ans,cnt[i]);
}
void del(int i){
t[cnt[i]]--;
if(cnt[i]==Ans && !t[cnt[i]])Ans--;
t[--cnt[i]]++;
}
signed main(){
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&d[i]);
a[i]=d[i];
}
sort(d+1,d+n+1);
int lenth=unique(d+1,d+n+1)-d-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(d+1,d+lenth+1,a[i])-d;
}
int len=sqrt(n);
for(int i=1;i<=m;i++){
int l,r;
scanf("%lld%lld",&l,&r);
q[i]={l,r,i,l/len};
}
sort(q+1,q+m+1,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++){
int ll=q[i].l;
int rr=q[i].r;
while(l>ll)add(a[--l]);
while(r<rr)add(a[++r]);
while(l<ll)del(a[l++]);
while(r>rr)del(a[r--]);
ans[q[i].id]=Ans;
}
for(int i=1;i<=m;i++){
printf("%lld\n",-ans[i]);
}
return 0;
}
莫队讲解
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18682408
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步