P12525 [Aboi Round 1] 私は雨 怎么可以酱紫啊

不是,怎么因为 \(lastans\) 不清空虚空调了一个半小时。

题意

给定一个序列,每次询问求区间 \(l\)\(r\) 内值域 \(a\)\(b\) 中模 \(p\) 意义下余 \(x\) 的数有多少个。

做法

这种模意义下的东西一眼根号分治啊,考虑对于 \(p\) 进行根号分治。

  • \(p > \sqrt V\)

注意到此时模 \(p\) 意义下为 \(x\) 的数一共只有 \(O(\sqrt V)\) 个,直接枚举这些数,值域限制判断一下当前你枚举出来的数是否在 \(a\)\(b\) 之间就可以了。

于是我们现在需要能快速查找形如区间内 \(x\) 的个数的数据结构,如果你使用什么主席树就不太平衡,又因为强制在线,考虑分块。

我们不妨记 \(f_{i,j}\) 表示前 \(i\) 个块内 \(j\) 出现的个数,对于每次询问的整块,我们用两个前缀和数组相减就能 \(O(1)\) 得出整块的贡献。

考虑散块怎么做,如果你想到记块内前缀和的话,那你分块大抵是学傻了,没有必要对散块进行枚举 \(x\),直接暴力判断散块内元素就好了。

  • \(p \le \sqrt V\)

这一部分内 \(p\) 的取值一共也只有 \(O(\sqrt V)\) 个,于是我们考虑对于每一个取值都记录出一个序列出来。

然后对于每一个取值的序列我们按它取值后的值排序,并且以在原序列中的下标为第二关键字排序,然后再对这 \(O(\sqrt V)\) 个序列进行分块。

对于每个块,我们存 \(valmax _{i,j}\) 表示在模 \(i\) 这个序列上第 \(j\) 个块的值的最大值,\(valmin _{i,j}\) 表示在模 \(i\) 这个序列上第 \(j\) 个块的值的最小值,\(idmax _{i,j}\) 表示在模 \(i\) 这个序列上第 \(j\) 个块在原序列下标的最大值,\(idmin _{i,j}\) 表示在模 \(i\) 这个序列上第 \(j\) 个块在原序列下标的最小值。

你维护这一坨东西,就可以定位出 \(l,r,p,x\) 对应我们模后的序列的左端点和右端点了。

注意到此时若没有值域限制就可以直接快乐的做了,但是还有一个抽象的值域限制,于是我们搞一些令人窒息的操作 —— 继续值域分块,考虑 \(g_{i,j,k}\) 表示在模 \(i\) 这个序列上前 \(j\) 个块内原序列值域属于前 \(k\) 个值域块内的数有多少个,然后这是一个二维前缀和,你可以差分一下得到整块的答案。

考虑值域块散块怎么做,其实和 \(p>\sqrt n\) 的做法差不多,直接暴力枚举就好了。

分析一下复杂度,考虑 \(n\)\(V\) 基本同阶,所以时空复杂度均为 \(O(n\sqrt n)\)

代码

注意到这种东西卡常极度严重,我的代码长得太丑,要靠评测机波动,所以放一个没卡常的代码得了,想要完整版可以私信我。

#include<bits/stdc++.h>
using namespace std;
int n,type;
const int S=600,N=100005,P=650,V=200005,T=600;
int a[1000001],bel[1000001],L[1000001],R[1000001],bl[1000001],blL[1000001],blR[1000001],f[N/S+15][V],idmin[P+5][N/S+15],idmax[P+5][N/S+15],valmin[P+5][N/S+15],valmax[P+5][N/S+15];
int g[P+5][N/S+5][V/T+5];
struct node{
	int id,val,yuanzhi;
}q[P+5][N+5];
int e[P+5][N+5];
inline int ask(int l,int r,int A,int B,int p,int x){
	int ans=0;
	if(bel[l]==bel[r]){
		for(int i=l;i<=r;i++){
			if(A<=a[i]&&a[i]<=B&&a[i]%p==x){
				ans++;
			}
		}
	}else{
		for(int i=l;i<=R[bel[l]];i++){
			if(A<=a[i]&&a[i]<=B&&a[i]%p==x){
				ans++;
			}
		}
		for(int i=L[bel[r]];i<=r;i++){
			if(A<=a[i]&&a[i]<=B&&a[i]%p==x){
				ans++;
			}
		}
		for(int i=x;i<=V;i+=p){
			if(i>=A&&i<=B)ans+=f[bel[r]-1][i]-f[bel[l]][i];
		}
	}
	return ans;
}
inline int askl(int l,int p,int x){
	for(int i=1;i<=bel[n];i++){
		if(valmin[p][i]>x)return -1;
		if(valmax[p][i]>=x&&valmin[p][i]!=valmax[p][i]){
			for(int j=L[i];j<=R[i];j++){
				if(q[p][j].val==x&&q[p][j].id>=l)return j;
			}
		}
		if(valmin[p][i]==valmax[p][i]&&valmin[p][i]==x){
			if(idmax[p][i]>=l){
				for(int j=L[i];j<=R[i];j++){
					if(q[p][j].id>=l)return j;
				}
			}
		}
	}
	return -1;
}
inline int askr(int r,int p,int x){
	for(int i=bel[n];i>=1;i--){
		if(valmax[p][i]<x)return -1;
		if(valmin[p][i]<=x&&valmin[p][i]!=valmax[p][i]){
			for(int j=R[i];j>=L[i];j--){
				if(q[p][j].val==x&&q[p][j].id<=r)return j;
			}
		}
		if(valmin[p][i]==valmax[p][i]&&valmin[p][i]==x){
			if(idmin[p][i]<=r){
				for(int j=R[i];j>=L[i];j--){
					if(q[p][j].id<=r)return j;
				}
			}
		}
	}
	return -1;
}
inline int query(int bkl,int bkr,int l,int r,int A,int B,int p,int x){
	if(l==-1||r==-1||r<l)return 0;
	int ans=0;
	if(bl[A]==bl[B]){
		for(int i=A;i<=B;i++){
			if(i%p==x){
				ans+=f[bkr][i]-f[bkl-1][i];
			}
		}
	}else{
		if(bel[l]==bel[r]){
			for(int i=l;i<=r;i++){
				if(q[p][i].yuanzhi>=A&&q[p][i].yuanzhi<=B)ans++;
			}
		}else{
			for(int i=A;i<=blR[bl[A]];i++){
				if(i%p==x){
					ans+=f[bkr][i]-f[bkl-1][i];
				}
			}
			for(int i=blL[bl[B]];i<=B;i++){
				if(i%p==x){
					ans+=f[bkr][i]-f[bkl-1][i];
				}
			}
			for(int i=l;i<=R[bel[l]];i++){
				if(q[p][i].yuanzhi>=blR[bl[A]]+1&&q[p][i].yuanzhi<=blL[bl[B]]-1){
					ans++;
				}
			}
			for(int i=L[bel[r]];i<=r;i++){
				if(q[p][i].yuanzhi>=blR[bl[A]]+1&&q[p][i].yuanzhi<=blL[bl[B]]-1){
					ans++;
				}
			}
			ans=ans+g[p][bel[r]-1][bl[B]-1]-g[p][bel[r]-1][bl[A]]-g[p][bel[l]][bl[B]-1]+g[p][bel[l]][bl[A]];
		}
	}
	return ans;
}
int tot[N+15];
signed main(){
	memset(idmin,0x3f,sizeof(idmin));
	memset(valmin,0x3f,sizeof(valmin));
	cin>>n>>type;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	} 
	for(int i=1;i<=P;i++){
		for(int j=1;j<=n;j++){
			e[a[j]%i][++tot[a[j]%i]]=j;
		}
		int cnt=0;
		for(int j=0;j<=i-1;j++){
			for(int k=1;k<=tot[j];k++){
				int v=e[j][k];
				q[i][++cnt].val=j;
				q[i][cnt].yuanzhi=a[v];
				q[i][cnt].id=v;
			}
			tot[j]=0;
		}
	}
	for(int i=1;i<=V;i++){
		bl[i]=(i-1)/T+1;
	}
	for(int i=1;i<=n;i++){
		bel[i]=(i-1)/S+1;
	}
	for(int i=1;i<=n;i++){
		for(int j=bel[i];j<=bel[n];j++) f[j][a[i]]++;
		R[bel[i]]=i;
	}
	for(int i=1;i<=P;i++){
		for(int j=1;j<=n;j++){
			idmin[i][bel[j]]=min(idmin[i][bel[j]],q[i][j].id);
			idmax[i][bel[j]]=max(idmax[i][bel[j]],q[i][j].id);
			valmin[i][bel[j]]=min(valmin[i][bel[j]],q[i][j].val);
			valmax[i][bel[j]]=max(valmax[i][bel[j]],q[i][j].val);
			g[i][bel[j]][bl[q[i][j].yuanzhi]]++;
		}
		for(int j=1;j<=bel[n];j++){
			for(int k=1;k<=bl[V];k++){
				g[i][j][k]+=g[i][j-1][k];
			}
		}
		for(int j=1;j<=bel[n];j++){
			for(int k=1;k<=bl[V];k++){
				g[i][j][k]+=g[i][j][k-1];
			}
		}
	}
	for(int i=V;i>=1;i--)blL[bl[i]]=i;
	for(int i=1;i<=V;i++)blR[bl[i]]=i;
	for(int i=n;i>=1;i--)L[bel[i]]=i;
	int m;
	cin>>m;
	int lasans=0;
	for(int i=1;i<=m;i++){
		int l,r,A,B,p,x;
		cin>>l>>r>>A>>B>>p>>x;
		l=l^lasans;
		r=r^lasans;
		A=A^lasans;
		B=B^lasans;
		p=p^lasans;
		x=x^lasans;
		lasans=0;
		if(bel[l]==bel[r]){
			for(int i=l;i<=r;i++){
				if(a[i]>=A&&a[i]<=B&&a[i]%p==x){
					lasans++;
				}
			}
		}else if(p>=P){
			lasans=ask(l,r,A,B,p,x);
		}else{
			for(int i=l;i<=R[bel[l]];i++){
				if(a[i]>=A&&a[i]<=B&&a[i]%p==x){
					lasans++;
				}
			}
			for(int i=L[bel[r]];i<=r;i++){
				if(a[i]>=A&&a[i]<=B&&a[i]%p==x){
					lasans++;
				}
			}
			int ll=askl(R[bel[l]]+1,p,x);
			int rr=askr(L[bel[r]]-1,p,x);
			lasans+=query(bel[l]+1,bel[r]-1,ll,rr,A,B,p,x);
		}
		cout<<lasans<<endl;
		lasans*=type;
	}
	return 0;
}
posted @ 2025-12-27 08:55  jerry1717  阅读(6)  评论(0)    收藏  举报