嗯,今天也是我第一次学分块,所以更下题解和分块.辛格大佬说这个题就是莫队的板子
分块一般是将一个区间分成sqrt(n)块,然后对于进行处理,比如说今天我们这个题目求区间众数.
我们处理出两个数组,一个f[i][j]表示第i块到第j块的众数是多少,另外一个s[i][j]表示前i块中j出现次数.处理完这两个数组,我们就很容易知道假如给定一个区间l-r要我们求这个区间的众数,怎么求呢?假设l-r不跨一个区间.那么直接暴力求就好了,假如跨的区间>1,那么众数产生会是哪些地方呢?我们画个图.
emm,有点丑...不过并不影响什么,显然众数只可能是f[2][4]和l-2/4-r里面的一个数,如此这个题就做完了..下面代码有注释的..
代码如下:
#include <bits/stdc++.h> using namespace std; const int N=4e4+5; const int M=2e2+10; int a[N],b[N];//a数组用来存值,b数组用来离散化 int f[M][M],s[M][N];//f数组是用来存第i块到第j块的众数,s数组是用来存前i块中值为j的数量有多少. int to[N],block,cnt;//开个桶数组.块的大小.块的数量 inline int ask(int x)//查询x在哪一块. { return (x-1)/block+1; } int main() { int n,m; scanf("%d%d",&n,&m);//m组查询. for(int i=1;i<=n;i++) { scanf("%d",&a[i]);//输入 b[i]=a[i]; } block=(int)sqrt(n);//块的大小 cnt=(n-1)/block+1;//块的数量 sort(a+1,a+1+n); int sum=unique(a+1,a+1+n)-a-1; for(int i=1;i<=n;i++)//离散化 { b[i]=lower_bound(a+1,a+1+sum,b[i])-a; } for(int i=1;i<=cnt;i++)//处理s数组 { for(int j=(i-1)*block+1;j<=min(n,i*block);j++) { s[i][b[j]]++; } for(int j=1;j<=sum;j++) { s[i][j]+=s[i-1][j]; } } int mx;//众数 for(int i=1;i<=cnt;i++)//处理f数组 { for(int j=i;j<=cnt;j++) { mx=f[i][j-1];//没选肯定众数是上一个区间的众数. for(int k=(j-1)*block+1;k<=min(n,j*block);k++) { if(s[j][b[k]]-s[i-1][b[k]]>s[j][mx]-s[i-1][mx]||(s[j][b[k]]-s[i-1][b[k]]==s[j][mx]-s[i-1][mx]&&b[k]<mx)) { mx=b[k]; } } f[i][j]=mx; } } int ans=0,_l,_r; while(m--) { scanf("%d%d",&_l,&_r); int l=(_l+a[ans]-1)%n+1; int r=(_r+a[ans]-1)%n+1; if(l>r) swap(l,r); if(ask(r)-ask(l)<=1) { for(int i=l;i<=r;i++) { to[b[i]]++; } for(int i=l;i<=r;i++) { if(to[b[i]]>to[ans]||(to[b[i]]==to[ans]&&b[i]<ans)) { ans=b[i]; } } for(int i=l;i<=r;i++) to[b[i]]=0; } else { int bl=ask(l); int br=ask(r); ans=f[bl+1][br-1];//中间是众数. for(int i=l;i<=bl*block;i++) to[b[i]]++; for(int i=(br-1)*block+1;i<=r;i++) to[b[i]]++; for(int i=l;i<=bl*block;i++) { if((to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]>to[ans]+s[br-1][ans]-s[bl][ans])||(to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]==to[ans]+s[br-1][ans]-s[bl][ans]&&b[i]<ans)) { ans=b[i]; } } for(int i=(br-1)*block+1;i<=r;i++) { if((to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]>to[ans]+s[br-1][ans]-s[bl][ans])||(to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]==to[ans]+s[br-1][ans]-s[bl][ans]&&b[i]<ans)) { ans=b[i]; } } //清空 for(int i=l;i<=bl*block;i++) to[b[i]]=0; for(int i=(br-1)*block+1;i<=r;i++) to[b[i]]=0; } cout<<a[ans]<<endl; } return 0; }
友情提示下两个易错点,注意是对离散化的答案取模,以及分块的中间块的处理..