【题解】洛谷P5048 Yuno loves sqrt technology III

洛谷P5048 Yuno loves sqrt technology III

题意

给你一个长为 (n)的序列 (a)(m) 次询问,每次查询一个区间的众数的出现次数,强制在线。

(1leq n,m leq 5 imes 10^5,0leq a_ileq 10^9)

题解

分块,设块长为(S),先预处理第(i)块到第(j)块的众数的出现次数(f[i][j]),对于值域于中的每一个值,用vector按顺序记录(a)中出现该值的下标,同时记录(a)中每个元素在其对应vector中的下标。对于每一次询问(l,r),假设其包含的连续完整块的答案为(ans),由于非完整块中的元素最多(2S)个,故最多使答案增加(2S),我们依次检查这些元素能否是答案增大。对于左边的非完整块的元素(a_i),若其对应vector为(g),其在(g)中的下标为(p),如果(g[p+ans])存在且(g[p+ans]leq r),说明(a_i)([l,r])中的出现次数不会比(ans)更差,故可直接++(ans);对于右边的元素同理。注意每个检查只是判定了能否使(ans)变为(ans+1),而某个位置上的值可能使答案不止增大1,故需对每个位置需用while循环来进行检查。

预处理部分时间复杂度(O((frac{n}{S})^2 imes S)=O(frac{n^2}{S})),询问部分复杂度(O(mS)),故总复杂度(O(frac{n^2}{S}+mS)),取(S=frac{n}{sqrt m})可得总复杂度(O(nsqrt m)),直接取(S=sqrt n),复杂度(O((n+m)sqrt n))也可通过。

#include <bits/stdc++.h>
#define pb(x) emplace_back(x)
using namespace std;
const int N=600100,M=1000;
int id[N],f[M][M],n,m,b[N],c[N],nm,d[N],a[N],bs;
vector<int> g[N];
int ck1(int ans,int x){
	int k=a[x],na=g[k].size(),p=d[x];
	if(p+ans<na)return g[k][p+ans];
	else return n+1;
}
int ck2(int ans,int x){
	int k=a[x],p=d[x];
	if(p-ans>=0)return g[k][p-ans];
	else return -1;
}
void f1(){
	scanf("%d%d",&n,&m);
	bs=sqrt(n)+1;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
		id[i]=(i-1)/bs+1;
	}
	nm=(n-1)/bs+1;
	sort(b+1,b+1+n);
	int np=unique(b+1,b+1+n)-b-1;
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+1+np,a[i])-b;
		g[a[i]].pb(i);d[i]=g[a[i]].size()-1;
		assert(g[a[i]][d[i]]==i);
	}
	for(int i=1;i<=nm;i++){
		int na=0;
		for(int j=1;j<=np;j++){c[j]=0;}
		for(int j=i;j<=nm;j++){
			int l=(j-1)*bs+1,r=min(l+bs-1,n);
			for(int k=l;k<=r;k++){
				c[a[k]]++;
				na=max(na,c[a[k]]);
			}	
			f[i][j]=na;
		}
		
	}
	int lstans=0;
	while(m--){
		int x,y;scanf("%d%d",&x,&y);
		x^=lstans;y^=lstans;
		int na=id[x],nb=id[y];
		int ans=0;
		if(na+1<=nb-1){ans=f[na+1][nb-1];}
		for(int i=min(y,na*bs);i>=x;i--){
			while(ck1(ans,i)<=y){
				++ans;
			}
		}
		for(int i=max(x,(nb-1)*bs+1);i<=y;i++){
			while(ck2(ans,i)>=x){
				++ans; 
			}
		}
		lstans=ans;
		printf("%d
",ans);
	}
}
int main(){
	f1();
	return 0;
}

/*
10 0
2 3 5 1 5 5 4 4 3 5 


4 1
2 3 3 3
2 4
*/
原文地址:https://www.cnblogs.com/bobh/p/15026514.html