数列分块入门 9 & 蒲公英

区间众数查询。

解法一

莫队,但是蒲公英有加密操作。

解法二

分块。

离散化+块内二分。

预处理出两块之间的众数。

将每一个数出现的位置塞进一个 vector,排序,在面对整块时选择一手二分。

#pragma GCC diagnostic error "-std=c++14"
#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
int n,bl,a[40010],q,cnt,val[40010],pos[40010],L[40006],R[40006];
vector<int> orz_twx[40006];
void discrete() {
	memcpy(val,a,sizeof a);
	sort(val+1,val+n+1);
	cnt=unique(val+1,val+n+1)-(val+1);
}
int query(int x) {
	return lower_bound(val+1,val+cnt+1,x)-val;
}
int tot[40006],now,ma,f[806][806];
void pre(int x) {
	now=ma=0;
	memset(tot,0,sizeof tot);
	for(int i=L[x];i<=n;i++) {
		if(++tot[a[i]]>ma||(tot[a[i]]==ma&&a[i]<now))
		    now=a[i],ma=tot[a[i]];
		f[x][pos[i]]=now;
	}
}
int lans=0;
int find(int x,int l,int r) {
	return upper_bound(orz_twx[x].begin(),orz_twx[x].end(),r)-lower_bound(orz_twx[x].begin(),orz_twx[x].end(),l);
}
void work(int x,int l,int r,int &ans,int &cnt) {
	int w=find(x,l,r);
	if(w>cnt||(w==cnt&&x<ans))
		cnt=w,ans=x;
}
int query(int l,int r) {
	int ans=0,cnt=0;
	if(pos[l]==pos[r]) {
		for(int i=l;i<=r;i++)
		    work(a[i],l,r,ans,cnt);
		return val[ans];
	}
	if(pos[l]+1<=pos[r]-1)
	    if(f[pos[l]+1][pos[r]-1])
	        work(f[pos[l]+1][pos[r]-1],l,r,ans,cnt);
	for(int i=l;i<=R[pos[l]];i++)
	    work(a[i],l,r,ans,cnt);
	for(int i=L[pos[r]];i<=r;i++)
	    work(a[i],l,r,ans,cnt);
	return val[ans];
}
int main() {
	scanf("%d %d",&n,&q);
	int bl=sqrt(log(n)/log(2)*n);
	int len=bl?n/bl:n;
	for (int i = 1; i <= n; i++) 
		scanf("%d",&a[i]);
	discrete();
	for(int i=1; i<=bl; i++)
		L[i]=(i-1)*len+1,R[i]=i*len;
	if(R[bl]<n) {
		L[bl+1]=R[bl]+1;
		R[++bl]=n;
	}
	for(int i=1;i<=bl;i++)
	    for(int j=L[i];j<=R[i];j++)
	        pos[j]=i;
	for(int i=1;i<=n;i++) {
		a[i]=query(a[i]);
	    orz_twx[a[i]].push_back(i);
	}
	for(int i=1;i<=bl;i++)
	    pre(i);
	for (int i = 1; i <= q; i++) {
		int x,y;
		scanf("%d %d",&x, &y);
		x=(x+lans-1)%n+1,y=(y+lans-1)%n+1;
		if(x>y)
		    swap(x,y);
		//printf("true is %d and %d
",x,y);
		printf("%d
",lans=query(x, y));
	}
	return 0;
}

如上为蒲公英的 AC 代码。

原文地址:https://www.cnblogs.com/lajiccf/p/12901577.html