【洛谷5048】[Ynoi2019 模拟赛] Yuno loves sqrt technology III(分块妙题)

点此看题面

  • 给定一个长度为(n)的序列,(q)次询问区间众数的出现次数。
  • (n,qle5 imes10^5),强制在线

分块预处理+询问

不得不说是非常妙的一道题。

考虑预处理的时候我们求出(f_{i,j})表示(isim j)的块中的区间众数的出现次数,这只要枚举起始块(i)然后不断往里面加数即可,时间复杂度(O(nsqrt n)),空间复杂度(O(n))

对于询问,我们先初始化答案为中间那些完整块的众数出现次数。

然后考虑两边的散块,我们初始对于每种值开个(vector)存在它在序列中出现的位置,并对于每个位置记录它在其值对应的(vector)中的下标。

那么我们枚举左边的散块中的数,就只要判断从它向后算起第(ans+1)个数是否还在询问区间内,能就不断将(ans)(1)

同理,枚举右边散块中的数判断从它向前算起第(ans+1)个数是否还在询问区间内更新答案。

显然散块中数的个数是(O(sqrt n))的,那么答案最多变化(O(sqrt n)),复杂度正确。

代码:(O(nsqrt n))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500000
#define M 720
using namespace std;
int n,ans,a[N+5],sz,bl[N+5],dc,dv[N+5],rk[N+5];vector<int> p[N+5];
namespace FastIO
{
	#define FS 100000
	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
');}
}using namespace FastIO;
int g[N+5],f[M+5][M+5];I void Build()//初始化
{
	RI i,j,k;for(i=1;i<=bl[n];++i)//枚举起始块
	{
		for(j=i;j<=bl[n];++j) for(f[i][j]=f[i][j-1],//不断往里面加块
			k=(j-1)*sz+1;k<=min(j*sz,n);++k) ++g[a[k]]>f[i][j]&&(f[i][j]=g[a[k]]);//更新最大出现次数
		for(j=(i-1)*sz+1;j<=n;++j) --g[a[j]];//清空桶
	}
}
I void BF_L(CI l,CI r,CI R)//暴力做左边的散块
{
	for(RI i=l;i<=r;++i) W(rk[i]+ans<p[a[i]].size()&&p[a[i]][rk[i]+ans]<=R) ++ans;//从它向后第ans+1个数
}
I void BF_R(CI l,CI r,CI L)//暴力做右边的散块
{
	for(RI i=l;i<=r;++i) W(rk[i]>=ans&&p[a[i]][rk[i]-ans]>=L) ++ans;//从它向前第ans+1个数
}
int main()
{
	RI Qt,i;for(read(n,Qt),sz=sqrt(n),i=1;i<=n;++i) read(a[i]),dv[i]=a[i],bl[i]=(i-1)/sz+1;
	for(sort(dv+1,dv+n+1),dc=unique(dv+1,dv+n+1)-dv-1,i=1;i<=n;++i)//离散化
		rk[i]=p[a[i]=lower_bound(dv+1,dv+dc+1,a[i])-dv].size(),p[a[i]].push_back(i);//记录每个位置在对应vector中的下标
	RI l,r;Build();W(Qt--) read(l,r),l^=ans,r^=ans,bl[l]==bl[r]?(ans=0,BF_L(l,r,r))//同个块中直接暴力
		:(ans=f[bl[l]+1][bl[r]-1],BF_L(l,bl[l]*sz,r),BF_R((bl[r]-1)*sz+1,r,l)),writeln(ans);//初始化答案为整块答案,暴力做散块
	return clear(),0;
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5048.html