本文主要是介绍BZOJ2724 [Violet 6]蒲公英 解题报告【数据结构】【分块】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Description
Input
修正一下
l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1
Output
Sample Input
6 3
1 2 3 2 1 2
1 5
3 6
1 5
Sample Output
1
2
1
HINT
修正下:
n <= 40000, m <= 50000
解题报告
传说中这是一道分块的经典题。
我们不难看出,这道题要我们强制在线,加上只是查找众数没有更改,不方便合并区间,让人不由自主地想到了分块。那么这个题用分块怎么做呢?
我们又均值不等式得,分成sqrt(n)块时时间复杂度最低。我们先预处理出几个值:
-f[i][j] 存储这样一个pair:(第i到第j块分块出现的次数最多的数的次数,这个数的值的负值)。由于我们知道比较pair的最大值是先比first再比second,这样一来就可以保证这个数组是最优的。
-s[i][j] 代表前i块中j这个数出现的次数的和(前缀和)。
由于这个题不可能直接开一个筒来存储每一个数出现的次数,我们的方法是先将原数组排序,离散化,再将进行这些操作之前的这个数组每个元素的排名存储下来。往后我们存储次数的时候就直接存储排名,而非元素本身。
要点似乎就是这些,代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
const int N=4e4;
const int M=350;
int n,m,blk,cnt;
int lasans;
int a[N+5],b[N+5],c[N+5],bl[N+5],L[M+5],R[M+5],s[M+5][N+5];
pair<int,int>f[M+5][M+5];
int temp[N+5];
int query(int lf,int rg)
{pair<int,int>ret=f[bl[lf]+1][bl[rg]-1];if(bl[lf]==bl[rg])//在同一块里边,暴力 {for(int i=lf;i<=rg;i++)temp[b[i]]=0;for(int i=lf;i<=rg;i++)ret=max(ret,make_pair(++temp[b[i]],-b[i]));}else//不再同一块里,答案要么就是f[bl[lf]+1][bl[rg]-1],要么就是不再上述块中的数在[lf,rg]中出现的次数 {for(int i=lf;i<=R[bl[lf]];i++)temp[b[i]]=s[bl[rg]-1][b[i]]-s[bl[lf]][b[i]];//左边的零头中的元素在整块内的个数 for(int i=L[bl[rg]];i<=rg;i++)temp[b[i]]=s[bl[rg]-1][b[i]]-s[bl[lf]][b[i]];//右边的零头中的元素在整块内的个数 for(int i=lf;i<=R[bl[lf]];i++)ret=max(ret,make_pair(++temp[b[i]],-b[i]));//左边的零头中的元素在查询区间内的个数for(int i=L[bl[rg]];i<=rg;i++)ret=max(ret,make_pair(++temp[b[i]],-b[i]));//右边的零头中的元素在查询区间内的个数}return -ret.second;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];sort(a+1,a+1+n);a[0]=unique(a+1,a+1+n)-a-1;//离散化 for(int i=1;i<=n;i++)b[i]=lower_bound(a+1,a+1+a[0],b[i])-a;//在b数组中存储排名 blk=sqrt(n);if(n%blk)cnt=n/blk+1;else cnt=n/blk;for(int i=1;i<=n;i++)bl[i]=(i-1)/blk+1;for(int i=1;i<=cnt;i++)L[i]=(i-1)*blk+1,R[i]=i*blk;R[cnt]=n;for(int i=1;i<=cnt;i++){memset(c,0,sizeof(c));pair<int,int>now(0,0);for(int j=L[i];j<=n;j++){c[b[j]]++;now=max(now,make_pair(c[b[j]],-b[j]));//计算出第i块到第j块的答案和他的值 f[i][bl[j]]=now;}for(int j=1;j<=a[0];j++)s[i][j]=s[i-1][j];for(int j=L[i];j<=R[i];j++)s[i][b[j]]++;//前缀和 }while(m--){int l,r;scanf("%d%d",&l,&r);int lf=(l+lasans-1)%n+1,rg=(r+lasans-1)%n+1;if(lf>rg)swap(lf,rg);lasans=a[query(lf,rg)];//返回的只是排名 printf("%d\n",lasans);}return 0;
}
这篇关于BZOJ2724 [Violet 6]蒲公英 解题报告【数据结构】【分块】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!