求助分块5pts
查看原帖
求助分块5pts
759389
______l______楼主2022/9/25 15:12

按第一篇题解的思路去写的 具体思路在代码注释里 除了18其它全WA

#include<bits/stdc++.h>
//#pragma GCC optimize(3,"Ofast","inline")
//#define int long long
using namespace std;
const int N=1e5+10,sqrtN=sqrt(N);int n,m,q;
int a[N],x[N],ans[sqrtN][sqrtN],s[sqrtN][N],p[N];
int l[sqrtN],r[sqrtN],t,num;
/*
ans[i][j]:块i~块j的众数
s[i][j]:前i块中x[j]出现的次数(j是离散化编号)
*/
inline int time10(int x)
{return(x<<3)+(x<<1);}
inline int read(){//快读
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		if(ch==-1)exit(0);
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
		x=time10(x)+(ch^48),ch=getchar();
	return x*f;
}
inline void write(int x){//快写
	if(x<0)putchar('-'),x=-x;
	if(x<10){putchar(x+48);return;}
	write(x/10);putchar(x%10+48);
}
inline int name(int k){//查k的离散化编号
	return lower_bound(x+1,x+m+1,k)-x;
}
inline void init(int k){//分块
	p[k]=k/t+1;//块的编号
	if(p[k]!=p[k-1])//和上一个数不是同一个块
		r[p[k-1]]=k-1,l[p[k]]=k;//这两个数是块的边界
	if(k==n)r[p[k]]=k;//最后一个数
}int cnt[N],cut[N];
inline int ask(int ql,int qr,int x){//查询块ql~块qr中x出现的次数
	int k=name(x);
	return s[qr][k]-s[ql-1][k];
}//前缀和
inline int query(int ql,int qr){//询问O(sqrt n)
	memset(cnt,0,sizeof cnt);//清零
	if(p[qr]-p[ql]<=1){//中间没有完整块
		int as=INT_MAX,ar=0;//记录
		for(int i=ql;i<=qr;i++){//暴力求答案
			int k=name(a[i]);
			cnt[k]++;
			if(cnt[k]>ar||(cnt[k]==ar&&a[i]<as))
				ar=cnt[k],as=a[i];
		}return as;
	}if(l[p[ql]]==ql&&r[p[qr]]==qr)//边界的两数
		return ans[p[ql]][p[qr]];
	int ans1=ans[p[ql]+1][p[qr]-1];
	int cnt1=ask(p[ql]+1,p[qr]-1,ans1);
	//答案1:中间整块的众数
	int ans2=INT_MAX,cnt2=0;
	//答案2:整块边的数+这个数在中间整块中出现次数
	for(int i=ql;i<=r[p[ql]];i++){//ql所在块
		int k=name(a[i]);cnt[k]++;
		if(cnt[k]==1)//第一次记录
			cnt[k]+=ask(p[ql]+1,p[qr]-1,a[i]);//将中间的也加上
		if(cnt[k]>cnt2||(cnt[k]==cnt2&&a[i]<ans2))//赋值
			cnt2=cnt[k],ans2=a[i];
	}
	for(int i=l[p[qr]];i<=qr;i++){//qr所在块
		int k=name(a[i]);cnt[k]++;//同上
		if(cnt[k]==1)
			cnt[k]+=ask(p[ql]+1,p[qr]-1,a[i]);
		if(cnt[k]>cnt2||(cnt[k]==cnt2&&a[i]<ans2))
			cnt2=cnt[k],ans2=a[i];
	}//cout<<ans1<<":"<<cnt1<<"/"<<ans2<<":"<<cnt2<<"——";
	return(cnt1>cnt2||(cnt1==cnt2&&ans1<ans2))?ans1:ans2;//选择答案
}
signed main(){
	n=read(),q=read();t=sqrt(n);num=n/t+1;
	for(int i=1;i<=n;i++)//输入
		a[i]=read(),x[i]=a[i],init(i);
	sort(x+1,x+n+1);
	m=unique(x+1,x+n+1)-x;
	/*离散化*/
	int ks=INT_MAX,kr=0;
	/*O(n)*/
	for(int i=1;i<=num;i++)//枚举整块
		for(int j=l[i];j<=r[i];j++){//预处理s数组
			int xh=name(a[j]);
			cnt[xh]++;
			if(cnt[xh]>kr||(cnt[xh]==kr&&a[j]<ks))
				kr=cnt[xh],ks=a[j];//无视就好
			s[i][xh]=cnt[xh];
		}
	int ts=INT_MAX,tr=0;
	/*O(n sqrt n)*/
	for(int i=1;i<=num;i++){//枚举<起点>
		memset(cut,0,sizeof cut);//归零
		ts=INT_MAX,tr=0;//记录答案
		for(int j=i;j<=num;j++){//枚举块&自己
			for(int k=l[j];k<=r[j];k++){//
				int xh=name(a[k]);
				cut[xh]++;
				if(cut[xh]>tr||(cut[xh]==tr&&a[k]<ts))
					tr=cut[xh],ts=a[k];
			}ans[i][j]=ts;//保存答案
//			cout<<"第"<<l[i]<<"到第"<<r[j]<<":"<<ans[i][j]<<"\n";
		}
	}int answer=0;//上一次询问答案
	while(q--){
		int sl=read(),sr=read();
		int ql=((sl+answer-1)%n)+1;
		int qr=((sr+answer-1)%n)+1;
//		cout<<ql<<"~"<<qr<<":";
		if(ql>qr)swap(ql,qr);
		write(answer=query(ql,qr)),
		putchar('\n');//输出
	}fclose(stdin);
	fclose(stdout);
	return 0;
}

蒟蒻求助!!!

2022/9/25 15:12
加载中...