suxxsfe

一言(ヒトコト)

P4168 蒲公英

神仙分块,把减写成加调了半小时。。
不过这题也启示我们其实有的分块题要把多个块的信息拿到一起维护
以前做的都是每个块的信息单独维护
写的分块题还不太多,同时维护一个块的左右边界好像有点冗余,不过这样代码看起来更简单

洛谷P4168 [Violet]蒲公英

题意

给你长度为\(n\)的数组\(a\)\(m\)次询问,每次询问\([l,r]\)的众数
如果众数有多个,输出最小的一个
强制在线

输入格式

第一行两个整数\(n,m\) ,表示有\(n\)株蒲公英,\(m\) 次询问。
接下来一行n个空格分隔的整数\(a_i\),表示蒲公英的种类
再接下来m 行每行两个整数\(l_0,r_0\),我们令上次询问的结果为\(x\)(如果这是第一次询问, 则 \(x=0\))。
\(l=(l_0+x-1)\bmod n + 1,r=(r_0+x-1) \bmod n +1\),如果 \(l>r\),则交换 \(l,r\)
最终的询问区间为\([l,r]\)

输出格式

输出\(m\) 行。每行一个整数,表示每次询问的结果。

数据范围

对于 100% 的数据,保证\(1\leq n \leq 40000,1\leq m \leq 50000,1\leq a_i \leq 10^9\)


首先看到\(a_i\leq 10^9\),这题的问题有和每个数的数值有关系,所以考虑先离散化

一般使用分块时,如果\(l,r\)在同一个块或者在两个相邻的块(即\(belong_r-belong_l\leq 1\)),肯定是要暴力处理,复杂度\(O(\sqrt{n})\)
所以先考虑这部分怎么做
可以开一个\(tmp\)数组,\(tmp_i\)表示\(i\)这个值(肯定是离散化以后的值)出现了多少次
然后再用一个\(maxpos\)指向当前出现数量最多的数,一旦\(tmp_i>tmp_{maxpos}\)或者\(tmp_i=tmp_{maxpos},i<maxpos\),就让\(maxpos\)指向\(i\)
然后最后的\(maxpos\)就是我们要找的众数,复杂度可以是\(O(r-l)\),在\(r-l\)远小于\(n\)的时候应该用这种方法,在这里就是\(O(\sqrt{n})\)

再去考虑其它情况
对于\([l,r]\),我们设它们之间包含的整的块的区间是\([l',r']\),也就是说\([l,l'),(r',r]\)分别是左右两边的边角块
那么\([l,r]\)的众数有两种情况

  • \([l,l'),(r',r]\)中的数,在\([l,r]\)的出现次数最多的那个,也小于\([l',r']\)的众数在\([l,r]\)的出现次数,那么\([l,r]\)的众数就是\([l',r']\)的众数
  • \([l,l'),(r',r]\)中的数,在\([l,r]\)的出现次数最多的那个,大于\([l',r']\)的众数在\([l,r]\)的出现次数,或者他们相等,但这个数比\([l',r']\)的众数要小,那么\([l,r]\)的众数肯定就是这个数

当然上面说的“最多”,也是如果一样多就取数值较小的

关于怎么求\([l,l'),(r',r]\)中每个数在\([l,r]\)的出现次数,首先还是像那个暴力一样,统计这些数在左右边角块的出现次数
再用一个\(tag_i\)表示\(i\)这个数,目前有没有统计在\([l',r']\)的出现次数,如果统计了就不在加了,如果没有统计就加上他在\([l',r']\)的出现次数,然后\(tag_i=1\)
\([l',r']\)中的次数,我们可以维护一个\(sum_{i,j}\)表示前\(i\)个块,\(j\)出现了几次,就是个前缀和,一减就行

那么我们预处理的时候,要预处理出对于任意\(r\geq l\),第\(l\)个块到第\(r\)个块的众数
这个可以枚举每个\(l\),用之前暴力做法去做,就是每累计一个块记录一次答案,然后累计到最后一个块再清空,复杂度\(O(n\sqrt{n})\)
再就是之前说的那个前缀和,直接按定义求就行

然后\(tmp,tag\)的归零都不能用 memset ,否则就又成\(O(n)\)了,要一位位把之前改变过的位数清零,具体怎么做看代码

话说分块都好毒瘤,这题也是看了题解,然后知道了要维护那两个量才会的
不过好多题解都上来就把要预处理什么说出来,就体现不出思考的过程了
思考的时候肯定也是先想如果要求答案要知道什么,而不是先猜这个题要预处理出什么
如果是个套路题除外

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	int x=0,y=1;
	char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int n,m,block,blocknum,maxx;
int f[206][205],sum[206][40006];
int belong[40006];
int left[206],right[206];
int tmp[40006],maxpos,tag[40006];
struct data{
	int num,id,x;
}a[40006];
int what[40006];
inline void debug(){
	std::printf("blocknum : %d blocksize : %d\n",blocknum,block);
	std::printf("what : ");for(reg int i=1;i<=maxx;i++) std::printf("%d ",what[i]);EN;
	for(reg int i=1;i<=n;i++) std::printf("%d ",a[i].x);EN;
	for(reg int i=1;i<=blocknum;i++){
		std::printf("%d : ",i);
		for(reg int j=1;j<=maxx;j++) std::printf("%d ",sum[i][j]);
		EN;
	}
	for(reg int i=1;i<=blocknum;i++){
		for(reg int j=i;j<=blocknum;j++) std::printf("(%d %d): %d  ",i,j,f[i][j]);
		EN;
	}
}
inline int cmp(data x,data y){return x.num<y.num;}
inline int cmp2(data x,data y){return x.id<y.id;}
inline void pre(){
	for(reg int i=1;i<=blocknum;i++){
		for(reg int j=1;j<=maxx;j++) sum[i][j]=sum[i-1][j];
		for(reg int j=left[i];j<=right[i];j++) sum[i][a[j].x]++;
	}
	for(reg int i=1;i<=blocknum;i++){
		for(reg int j=i;j<=blocknum;j++){
			for(reg int k=left[j];k<=right[j];k++){
				tmp[a[k].x]++;
				if(a[k].x==maxpos) continue;
				if(tmp[a[k].x]>tmp[maxpos]||(tmp[a[k].x]==tmp[maxpos]&&a[k].x<maxpos)) maxpos=a[k].x;
			}
			f[i][j]=maxpos;
		}
		std::memset(tmp,0,sizeof tmp);maxpos=0;
	}
}
inline int baoli(int l,int r){
	for(reg int i=l;i<=r;i++){
		tmp[a[i].x]++;
		if(a[i].x==maxpos) continue;
		if(tmp[a[i].x]>tmp[maxpos]||(tmp[a[i].x]==tmp[maxpos]&&a[i].x<maxpos)) maxpos=a[i].x;
	}
	for(reg int i=l;i<=r;i++) tmp[a[i].x]=0;
	int ret=maxpos;maxpos=0;
	return ret;
}
inline int getans(int l,int r){
	reg int lblock=belong[l]+(left[belong[l]]!=l),rblock=belong[r]-(right[belong[r]]!=r);
	for(reg int i=l;i<left[lblock];i++){
		tmp[a[i].x]++;
		if(!tag[a[i].x]) tmp[a[i].x]+=sum[rblock][a[i].x]-sum[lblock-1][a[i].x],tag[a[i].x]=1;
		if(a[i].x==maxpos) continue;
		if(tmp[a[i].x]>tmp[maxpos]||(tmp[a[i].x]==tmp[maxpos]&&a[i].x<maxpos)) maxpos=a[i].x;
	}
	for(reg int i=right[rblock]+1;i<=r;i++){
		tmp[a[i].x]++;
		if(!tag[a[i].x]) tmp[a[i].x]+=sum[rblock][a[i].x]-sum[lblock-1][a[i].x],tag[a[i].x]=1;
		if(a[i].x==maxpos) continue;
		if(tmp[a[i].x]>tmp[maxpos]||(tmp[a[i].x]==tmp[maxpos]&&a[i].x<maxpos)) maxpos=a[i].x;
	}
	if(!tag[f[lblock][rblock]]) tmp[f[lblock][rblock]]=sum[rblock][f[lblock][rblock]]-sum[lblock-1][f[lblock][rblock]];
	int ret;
	if(tmp[maxpos]>tmp[f[lblock][rblock]]||(tmp[maxpos]==tmp[f[lblock][rblock]]&&maxpos<f[lblock][rblock])) ret=maxpos;
	else ret=f[lblock][rblock];
	for(reg int i=l;i<left[lblock];i++) tmp[a[i].x]=tag[a[i].x]=0;
	for(reg int i=right[rblock]+1;i<=r;i++) tmp[a[i].x]=tag[a[i].x]=0;
	tmp[f[lblock][rblock]]=tag[f[lblock][rblock]]=0;
	return ret;
}
int main(){
	n=read();m=read();block=std::sqrt(n);
	blocknum=std::ceil((double)n/block);
	left[1]=1;right[blocknum]=n;
	for(reg int i=1;i<=n;i++){
		a[i].num=read(),a[i].id=i;
		belong[i]=(i-1)/block+1;
		if(belong[i]!=belong[i-1]) left[belong[i]]=i,right[belong[i-1]]=i-1;
	}
	std::sort(a+1,a+1+n,cmp);
	maxx=0;
	for(reg int i=1;i<=n;){
		a[i].x=++maxx;what[maxx]=a[i].num;
		reg int last=i;
		for(i++;a[last].num==a[i].num;i++) a[i].x=maxx;
	}
	std::sort(a+1,a+1+n,cmp2);
	pre();
//		debug();
	reg int ans=0,l,r;
	while(m--){
		l=read();r=read();
		l=(l+ans-1)%n+1;r=(r+ans-1)%n+1;
		if(r<l) l^=r,r^=l,l^=r;
		if(belong[r]-belong[l]<=1) ans=baoli(l,r);
		else ans=getans(l,r);
		ans=what[ans];
		std::printf("%d\n",ans);
	}
	return 0;
}
posted @ 2020-03-31 10:36  suxxsfe  阅读(135)  评论(0编辑  收藏  举报