把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P5048 [Ynoi2019 模拟赛] Yuno loves sqrt technology III

题面传送门
很平凡的分块啊不知道为什么要评黑题。
首先显然要预处理块间众数。
然后就是考虑零散块怎么处理。
用一个vector将所有一样的数存下来,然后零散块左边从右到做遍历,如果碰到一个数后ans个数没有超过右边界就直接将ans++
右边同理。
时间复杂度\(O(n\sqrt n)\),因为vector常数太大所以可以直接把块长放到\(\frac{n}{3}\)这样子的。
code:

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 500000
#define K 1500
#define I inline
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,c[N+5],nows[N+5],tots[N+5],f[K+5][K+5],id[N+5],a[N+5],lastans,fr[K+5],en[K+5],ans,nx,ny;
I void ls(int &x){int l=0,r=n,mid;while(l+1<r) mid=l+r>>1,(nows[mid]<x?l:r)=mid;x=tots[r];}
vector<int> g[N+5];
int main(){
	freopen("1.in","r",stdin);
	register int i,j,h;scanf("%d%d",&n,&m);for(i=1;i<=n;i++)scanf("%d",&a[i]),nows[i]=a[i];k=sqrt(n/3);
	sort(nows+1,nows+n+1);for(tots[1]=1,i=2;i<=n;i++) tots[i]=tots[i-1]+(nows[i]!=nows[i-1]);
	for(i=1;i<=n;i++) ls(a[i]),g[a[i]].push_back(i),id[i]=g[a[i]].size()-1;
	for(i=0;i<=n/k;i++) fr[i]=max(i*k,1),en[i]=min(i*k+k-1,n);
	for(i=0;i<=n/k;i++){
		for(j=i;j<=n/k;j++){
			for(h=fr[j];h<=en[j];h++) c[a[h]]++,ans=max(ans,c[a[h]]);
			f[i][j]=ans;
		}
		memset(c,0,sizeof(c));ans=0;
	}
	while(m--){
		scanf("%d%d",&x,&y);x^=lastans;y^=lastans;nx=x/k;ny=y/k;
		if(nx+1>=ny){
			for(ans=0,i=x;i<=y;i++)c[a[i]]++,ans=max(ans,c[a[i]]);
			printf("%d\n",lastans=ans);for(i=x;i<=y;i++) c[a[i]]=0;continue;
		}
		ans=f[nx+1][ny-1];
		for(i=en[nx];i>=x;i--) if(id[i]+ans<g[a[i]].size()&&g[a[i]][id[i]+ans]<=y) ans++;
		for(i=fr[ny];i<=y;i++) if(id[i]>=ans&&g[a[i]][id[i]-ans]>=x) ans++;printf("%d\n",lastans=ans);
	}
}
posted @ 2021-05-04 20:37  275307894a  阅读(50)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end