把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷3709】大爷的字符串题(离散化+莫队)

点此看题面

大致题意: 算法标签——语文,给定一个数列,多组询问,每次询问一个区间内的众数出现的次数。

莫队

这道题的算法应该是莫队

如何用莫队求解此题

我们可以用\(cnt\)数组记录下每个数出现的次数(注意要先离散化),用\(tot\)数组记录下每个数在\(cnt\)数组中的出现次数,并用\(ans\)记录答案。

当我们要加入一个新数\(x\)的时候,如果加入前的\(cnt_x=ans\),则加入后的\(cnt_x\)肯定大于\(ans\),因此将\(ans\)\(1\)

当我们要删除一个数\(x\)的时候,如果删除前\(cnt_x=ans\)\(tot_{ans}=1\),则删除该元素后就没有元素的出现个数为\(ans\)了,因此将\(ans\)\(1\)

这样就可以了。

代码

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<0?-(x):(x))
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define Fsize 100000
#define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))
#define N 200000
int FoutSize=0,OutputTop=0;char Fin[Fsize],*FinNow=Fin,*FinEnd=Fin,Fout[Fsize],OutputStack[Fsize];
using namespace std;
int n,Q,blo,s,a[N+5],p[N+5],bl[N+5],cnt[N+5],tot[N+5],res[N+5];
struct Query
{
    int l,r,pos;
}q[N+5];
inline void read(int &x)
{
    x=0;static char ch;
    while(!isdigit(ch=tc()));
    while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
}
inline void write(int x)
{
    if(!x) return (void)pc('0');
    while(x) OutputStack[++OutputTop]=x%10+48,x/=10;
    while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;
}
inline bool cmp(Query x,Query y)//将询问排序
{
    return bl[x.l]^bl[y.l]?bl[x.l]<bl[y.l]:(bl[x.l]&1?x.r<y.r:x.r>y.r);
}
inline int find(int x)//求出离散化后的值
{
    register int l=1,r=s,mid;
    while(l<=r) p[mid=l+r>>1]<x?l=mid+1:r=mid-1;//二分查找
    return l;
}
int main()
{
    register int i;
    for(read(n),read(Q),blo=sqrt(n),i=1;i<=n;++i) read(a[i]),p[i]=a[i],bl[i]=(i-1)/blo+1;
    for(sort(p+1,p+n+1),s=unique(p+1,p+n+1)-p-1,i=1;i<=n;++i) a[i]=find(a[i]);//将原数组离散化
    for(i=1;i<=Q;++i) read(q[q[i].pos=i].l),read(q[i].r);
    register int L=1,R=1,ans=tot[1]=1;
    for(sort(q+1,q+Q+1,cmp),cnt[a[1]]=i=1;i<=Q;++i)//以下为莫队的主要过程
    {
        while(R<q[i].r) {++R,--tot[cnt[a[R]]],++tot[++cnt[a[R]]];if(cnt[a[R]]>ans) ++ans;}//将区间右边界增加
        while(L>q[i].l) {--L,--tot[cnt[a[L]]],++tot[++cnt[a[L]]];if(cnt[a[L]]>ans) ++ans;}//将区间的左边界减小
        while(R>q[i].r) {if(!--tot[cnt[a[R]]]&&!(cnt[a[R]]^ans)) --ans;++tot[--cnt[a[R--]]];}//将区间的右边界减小
        while(L<q[i].l) {if(!--tot[cnt[a[L]]]&&!(cnt[a[L]]^ans)) --ans;++tot[--cnt[a[L++]]];}//将区间的左边界增大
        res[q[i].pos]=ans;//用res[]数组存储答案
    }
    for(i=1;i<=Q;++i) (res?pc('-'):0),write(res[i]),pc('\n');//按读入的顺序输出答案
    return fwrite(Fout,1,FoutSize,stdout),0;
}
posted @ 2018-10-28 18:17  TheLostWeak  阅读(139)  评论(0编辑  收藏  举报