BZOJ 2506: calc【离线,值域分块

本文介绍了一种离线处理区间更新与查询的方法,通过预处理将不同范围内的操作进行分类,实现高效的更新与查询效率。针对不同规模的质数采用不同的策略,小质数时使用桶状结构进行更新,大质数时则采用枚举的方式。

……看到这么鬼畜的不好维护的区间,考虑离线,从左到右添加数列中的数

因为值域是1e4,考虑p<=100和p>100的情况。

p<=100的情况下,O(√值域)地更新,O(1)地查询;p>100的时候,O(1)地更新,O(√值域)地查询

添加每个数的时候,对于p<=100的情况的贡献直接累加;对于p>100的显然只有100左右个数对答案有贡献,于是枚举就好了

……反正这种套路我应该学不会x

#include<bits/stdc++.h>
#define MAXN 100005
#define MX 10005
using namespace std;	int n,m,mx;
int a[MAXN];
struct t1{
	int opt,pos,id,p,x;
	bool operator < (const t1 &ano) const{
		return pos < ano.pos;
	}
}Q[MAXN<<1];

int f1[105][105],f2[MX];

int ans[MAXN];

int read_l,read_r,read_p,read_x;
int main(){
//	freopen("1.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)	scanf("%d",a+i) , mx = max(mx,a[i]);
	for(int i=1;i<=m;++i){
		scanf("%d%d%d%d",&read_l,&read_r,&read_p,&read_x);
		Q[i] = (t1){-1,read_l-1,i,read_p,read_x};
		Q[i+m] = (t1){1,read_r,i,read_p,read_x};
	}
	int m2 = m<<1;
	sort(Q+1,Q+m2+1);
	
	for(int i=1,now=0;i<=m2;++i){
		while(now<Q[i].pos){
			++now;
			for(int j=1;j<=100;++j)	++f1[j][a[now]%j];
			++f2[a[now]];
		}
		if(Q[i].p<=100)
			ans[Q[i].id] += Q[i].opt * f1[Q[i].p][Q[i].x];
		else{
			int tmp = 0;
			for(int j=Q[i].x;j<=mx;j+=Q[i].p)
				tmp += f2[j];
			ans[Q[i].id] += Q[i].opt * tmp;
		}
	}
	for(int i=1;i<=m;++i)	printf("%d\n",ans[i]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值