您的位置:首页 > 理论基础 > 数据结构算法

BZOJ2724 [Violet 6]蒲公英 解题报告【数据结构】【分块】

2017-07-18 20:20 399 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐