bzoj 2724 蒲公英 分块

分块,预处理出每两个块范围内的众数,然后在暴力枚举块外的进行比较

那么怎么知道每一个数出现的次数呢?离散后,对于每一个数,维护一个动态数组就好了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#define N 40005
using namespace std;
int a[N],be[N],n,m,nn,cnt,val[N],c[N],tot;
int num[N];
map<int,int> mm;
vector <int > q[N];
int f[205][205];
int getnum(int l,int r,int x){
	return upper_bound(q[x].begin(),q[x].end(),r)-lower_bound(q[x].begin(),q[x].end(),l);
}
int query(int l,int r){
	int maxn=0,now=0;
	if(be[l]==be[r]){
		for(int i=l;i<=r;i++){
			int t=getnum(l,r,c[i]);
			if(t>maxn||(t==maxn&&a[i]<a[now])){
				maxn=t; now=i;
			}
		}
		return a[now];
	}
	now=f[be[l]+1][be[r]-1]; maxn=getnum(l,r,c[now]); 
	for(int i=l;i<=be[l]*nn;i++){
		int t=getnum(l,r,c[i]);
		if(t>maxn||(t==maxn&&a[i]<a[now])){
			maxn=t; now=i;}
	}
	for(int i=(be[r]-1)*nn+1;i<=r;i++){
		int t=getnum(l,r,c[i]);
		if(t>maxn||(t==maxn&&a[i]<a[now])){
			maxn=t; now=i;}
	}
	return a[now];
}
int main()
{
	scanf("%d%d",&n,&m); 
	nn=(int)sqrt(n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(!mm.count(a[i])) mm[a[i]]=++cnt;
		be[i]=(i-1)/nn+1;
		c[i]=mm[a[i]];
		q[c[i]].push_back(i);
	}
	tot=be[n]; int maxn,now;
	for(int i=1;i<=tot;i++){
		memset(num,0,sizeof(num)); maxn=0; now=0;
		for(int j=(i-1)*nn+1;j<=n;j++){
			num[c[j]]++;
			if(num[c[j]]>maxn||(num[c[j]]==maxn&&a[j]<a[now])){
				now=j; maxn=num[c[j]];
			}
			f[i][be[j]]=now;
		}
	}
	int ans=0,l,r;
	while(m--){
		scanf("%d%d",&l,&r);
		l=(l+ans-1+n)%n+1;
		r=(r+ans-1+n)%n+1;
		if(l>r) swap(l,r);
		ans=query(l,r);
		printf("%d\n",ans);
	}
	return 0;
}


posted @ 2017-07-15 12:50  Ren_Ivan  阅读(121)  评论(0编辑  收藏  举报