Luogu P4168 [Violet] 蒲公英 题解

发布时间 2023-10-29 22:00:32作者: Idtwtei

题目链接

[Violet] 蒲公英

分析

可以先将 \(a[i]\) 离散化
然后考虑分块
对于询问 \(x,y\)\(x\) 属于 \(p\), \(y\) 属于 \(q\)

\(q-p<=1\)

直接暴力枚举即可

\(else\) 如图

image
中间为分好块的地方
我们发现, \(ans\) 只可能为中间的众数或两边的的数
对于中间的众数,我们可以预处理出 \(z[i][j]\) 代表块 \(i\) 与块 \(j\) 之间的众数,时间复杂度为 \(O(n\sqrt{n})\)
对于两边的数,由于要考虑它们在中间出现的个数,所以先预处理出 \(cnt[i][j]\) 代表块 \(i\) 前, \(a[j]\) 的个数
再暴力枚举左右两侧即可

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N=40005,SN=405;

int id[N],a[N];
struct C{int id,w;}c[N];
bool cmp(C a,C b){return a.w<b.w;}

int fmp[N];
int tot=0;
int z[SN][SN],cnt[SN][N];
int cnt1[N],cnt2[N];
struct NODE{int l,r;}no[SN];

signed main(){
	int n,m;
	scanf("%lld %lld", &n, &m);
	int L=sqrt(n);
	for(int i=1;i<=n;i++){
		id[i]=(i-1)/L+1;
		if(id[i]!=id[i-1]) no[id[i]].l=i;
		if(i%L==0) no[id[i]].r=i;
		scanf("%lld", &a[i]);
		c[i].w=a[i];c[i].id=i;
	}
	no[id[n]].r=n;
	
	sort(c+1,c+n+1,cmp);//离散化 
	for(int i=1;i<=n;i++){
		if(c[i].w!=c[i-1].w) a[c[i].id]=++tot;
		else a[c[i].id]=tot;
		fmp[tot]=c[i].w;
	}
	
	for(int i=1;i<=n;i++){//预处理前缀和 
		if(id[i]!=id[i-1]) for(int j=1;j<=tot;j++) cnt[id[i]][j]=cnt[id[i-1]][j];
		cnt[id[i]][a[i]]++;
	}
	
	for(int i=1;i<=id[n];i++){//预处理众数 
		int ma=0;
		for(int j=i;j<=id[n];j++){
			int l=no[j].l,r=no[j].r;
			for(int k=l;k<=r;k++){
				int d=a[k];
				cnt1[d]++;
				if(cnt1[d]>cnt1[ma]) ma=d;
				else if(cnt1[d]==cnt1[ma]&&fmp[d]<fmp[ma]) ma=d;
			}
			z[i][j]=ma;
		}
		for(int j=1;j<=tot;j++) cnt1[j]=0;
	}
	
	int ans=0;
	for(int i=1;i<=m;i++){
		int x,y;scanf("%lld %lld", &x, &y);
		x=(x+ans-1)%n+1;y=(y+ans-1)%n+1;if(x>y) swap(x,y);
		
		int p=id[x],q=id[y];
		if(p==q||p==q-1){//情况一 
			ans=0;
			for(int j=x;j<=y;j++){
				int d=a[j];
				cnt2[d]++;
				if(cnt2[d]>cnt2[ans]) ans=d;
				else if(cnt2[d]==cnt2[ans]&&fmp[d]<fmp[ans]) ans=d;
			}				
			ans=fmp[ans];
			printf("%lld\n", ans);
			for(int j=x;j<=y;j++) cnt2[a[j]]=0;
		}
		else{//情况二 
			p++;q--;
			ans=z[p][q];
			for(int j=x;j<=no[p-1].r;j++){//左边 
				int d=a[j];
				cnt2[d]++;
				if(cnt2[d]+cnt[q][d]-cnt[p-1][d]>cnt2[ans]+cnt[q][ans]-cnt[p-1][ans]) ans=d;
				else if(cnt2[d]+cnt[q][d]-cnt[p-1][d]==cnt2[ans]+cnt[q][ans]-cnt[p-1][ans]&&fmp[d]<fmp[ans]) ans=d;
			}
			for(int j=no[q+1].l;j<=y;j++){//右边 
				int d=a[j];
				cnt2[d]++;
				if(cnt2[d]+cnt[q][d]-cnt[p-1][d]>cnt2[ans]+cnt[q][ans]-cnt[p-1][ans]) ans=d;
				else if(cnt2[d]+cnt[q][d]-cnt[p-1][d]==cnt2[ans]+cnt[q][ans]-cnt[p-1][ans]&&fmp[d]<fmp[ans]) ans=d;
			}
			ans=fmp[ans];printf("%lld\n", ans);
			//归零 
			for(int j=x;j<=no[p].l-1;j++) cnt2[a[j]]--;
			for(int j=no[q].r+1;j<=y;j++) cnt2[a[j]]--;
		}
	}
	return 0;
}