题目链接:
https://www.luogu.org/problem/P3948
先上一个差分数组的简介:
例如给出一个数组a[n]={0,1,3,6,4,8,2}
则差分数组d[n]={0,1,2,3,-2,4,-6}
(感觉上a[0]和d[0]一直都是将它默认为0,从下标1开始复制)
d[1]=a[1]-a[0]
d[2]=a[2]-a[1]
d[3]=a[3]-a[2]
…
d[n]=a[n]-a[n-1]
在这里先简单介绍一下差分数组:
数组a[7]={0,1,3,6,4,8,2}
则差分数组d[7]={0,1,2,3,-2,4,-6}
(感觉上a[0]和d[0]一直都是将它默认为0,从下标1开始复制)
d[1]=a[1]-a[0]
d[2]=a[2]-a[1]
d[3]=a[3]-a[2]
…
d[n]=a[n]-a[n-1]
性质①:a[i]=d[i]前缀和
a[1]=d[0]+d[1]
a[2]=d[0]+d[1]+d[2]
a[3]=d[0]+d[1]+d[2]+d[3]
…
a[n]=d[0]+d[1]+…+d[n-1]+d[n]
性质②
如果我们要对某个区间都+x,还是以上一个例子为例
数组a[7]={0,1,3,6,4,8,2}
差分数组d[7]={0,1,2,3,-2,4,-6}
若我们对a[2]-a[5]都+1,则有变化后的数组:
a[7]={0,1,4,7,5,9,2}
d[7]={0,1,3,3,-2,4,-7}
然后我们可以发现两个数组中变化了的只有加粗了的元素
在差分数组中d[2]=原d[2]+1,d[6]=原d[6]-1;
总结归纳就是:
若我们对数组a[n]的区间[l,r]+x;
对于差分数组d[n]的变化就是d[l]+=x,d[r+1]-=x;
对于本题:
前opt个操作:
用上面的性质②进行操作A
用性质①进行操作Q
后final个询问操作:
为了不t
先用性质①根据差分数组求出原值数组
然后对符合条件 min<=(T*imin<=(T∗i% mod)<=maxmod)<=max 进行记录
这样就可以每个询问都直接d[r]-d[l-1]了 //偷懒了直接用了差分数组来记录,这里可以再开一个数组的
ac代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
ll d[maxn],sum[maxn];
int n,opt,mod,minn,maxx,l,r,x;
int main(){
while(~scanf("%d%d%d%d%d",&n,&opt,&mod,&minn,&maxx)){
while(opt--){
char c[10];
scanf("%s",c);
if(c[0]=='A'){
scanf("%d%d%d",&l,&r,&x);
d[l]+=x; //性质②
d[r+1]-=x;
}else if(c[0]=='Q'){
scanf("%d%d",&l,&r);
int cnt=0;
for(int i=1;i<=r;i++){
sum[i]=d[i]+sum[i-1]; //性质①
if(i>=l&&sum[i]*i%mod>=minn&&sum[i]*i%mod<=maxx){
cnt++;
}
}
printf("%d\n",cnt);
}
}
//用性质①根据差分数组求出原值
for(int i=1;i<=n;i++){
sum[i]=d[i]+sum[i-1];
}
//记录符合条件的
for(int i=1;i<=n;i++){
sum[i]=sum[i]*i%mod;
if(sum[i]>=minn&&sum[i]<=maxx){
d[i]=d[i-1]+1;
}else{
d[i]=d[i-1];
}
}
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&l,&r);
printf("%d\n",d[r]-d[l-1]); //直接查询
}
}
}