P9212 题解

显然,我们维护的答案具有 可差分 性,所以转换为 \([1,r]\) 上的查询。

首先,对于 \(x,y,a_i\) 先对 \(m\) 取模不影响结果。

下面为了方便令 \(v = a_i\)

如果 \(x>y\)

则一定是 \(x+v-m<y+v\)

\(m \leq x+v\)\(y+v < m\)

转化为 \(m-x \leq v\)\(x<m-y\)

得到 \(v \in[m-x,m-y-1]\)

如果 \(x<y\)

答案为所有情况减去 \(x>y\) 的情况。

然后维护 \([1,r]\) 上的答案可以离线扫描一遍。

至此问题转化成维护一个集合,支持插入一个数以及查询 \(\bmod m\) 意义下 \(\in[m-x,m-y-1]\) 的数的数量。

考虑根号分治。

那么对于 \(m \leq \sqrt n\),我们记录所有 \(\bmod M = k\)(\(M \leq \sqrt n\)) 的数的出现次数,询问就直接回答。插入 \(O(\sqrt n)\),查询 \(O(\sqrt n)\)

\(m > \sqrt n\) 的情况下满足条件的数构成桶上不多于 \(\sqrt n\) 个区间,用 \(O(1)\) 查询 \(O(\sqrt n)\) 修改的值域分块即可。插入 \(O(\sqrt n)\),查询 \(O(\sqrt n)\)

如何写值域分块可以参考往期博客讲解

那么就 \(O( (n+q) \sqrt n)\) 的做完了。

参考代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+114;
struct Node{
	int x,y,M,id,f;//anser[id]+=f*v f = 1 or -1 
};
const int top = 100000;
const int B = 556;
vector<Node> A[maxn];//储存离线询问 
int a[maxn];
int anser[maxn];//输出答案 
struct block{
	int pre[1000];
}cnt[1000];
int cnt_pre[1001];
int ans[1001][1001];
int n,q;
inline void change(int x,int val){
	int sum = x/B;
	x%=B;
	if(x==0) sum--,x+=B;
	for(int i=x;i<=B;i++) {
		cnt[sum].pre[i]+=val;
	}
	for(int i=sum;i<=B;i++) cnt_pre[i]+=val;
}
inline int query(int l,int r){
	if(l>r) return 0;
	int lc=l/B;
	l%=B;
	int rc=r/B;
	r%=B;
	if(l==0) lc--,l+=B;
	if(r==0) rc--,r+=B;
	if(lc==rc) return cnt[lc].pre[r]-cnt[rc].pre[l-1];
	int res=0;
	res+=cnt[lc].pre[B]-cnt[lc].pre[l-1];
	res+=cnt[rc].pre[r];
	res+=cnt_pre[rc-1]-cnt_pre[lc];
	return res;
}
void set_add(int x){//向集合中插入 x 
	change(x,1);
	for(int j=1;j<B;j++){
		ans[j][x%j]++;
	}
}
inline int set_pre(int m,int k){//mod m 意义下小于等于 k 的数的数量 
	if(k<0) return 0;
	if(m<B)
	{
		int sum=0;
		for(int j=0;j<=k;j++){
			sum+=ans[m][j];
		}
		return sum;
	}
	else{
		int l=m,r=m+k,res=query(1,k);
		while(r<top){
			res+=query(l,r);
			l+=m;
			r+=m;
		}
		if(l<=top)
			res+=query(l,top);
		return res;
	}
}
inline int set_query(int m,int l,int r){//mod m \in [l,r]
	if(l>r||l<0||r<0) return 0;
	return set_pre(m,r)-set_pre(m,l-1);
}
void scan(){
	for(int i=1;i<=n;i++){
		set_add(a[i]);
		for(int j=0;j<A[i].size();j++){
			Node now = A[i][j];
			//处理询问 now
			if(now.x%now.M==now.y%now.M){
				anser[now.id]+=now.f*0;
			}
			else if(now.x%now.M>now.y%now.M){
				int l=now.M-now.x%now.M,r=now.M-now.y%now.M-1;
				anser[now.id]+=now.f*set_query(now.M,l,r);
			}
			else{
				int l=now.M-now.y%now.M,r=now.M-now.x%now.M-1;
				anser[now.id]+=now.f*(i-set_query(now.M,l,r));
			}
			
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=q;i++){
		int l,r,x,y,m;
		cin>>l>>r>>x>>y>>m;
		Node R,L;
		R.f=1;
		R.id=i;
		R.M=m;
		R.x=x;
		R.y=y;
		A[r].push_back(R);
		L.f=-1;
		L.id=i;
		L.M=m;
		L.x=x;
		L.y=y;
		A[l-1].push_back(L);
	}//询问离线
	scan();
	for(int i=1;i<=q;i++) cout<<anser[i]<<'\n';
}
posted @ 2024-01-30 23:52  ChiFAN鸭  阅读(9)  评论(0编辑  收藏  举报