题意:
给一个长度为n的a数组和b数组,b数组给固定值做分母,每次可以add a数组的一个区间,区间内的数全部加一,也可以query a数组区间内各个数模b数组的值的和
这道题单纯暴力或者线段树都是会TLE,需要用个sub数组来记录当前需要更新的最小值,每次需要add的时候sub就会-1,只有当sub[root]=0的时候才会更新lazy和sum
#include<bits/stdc++.h>
using namespace std;
const int MAXN=4e5+10;
int b[MAXN],sub[MAXN],sum[MAXN],lazy[MAXN];
void up(int root){
sum[root]=sum[root*2]+sum[root*2+1];
sub[root]=min(sub[root*2],sub[root*2+1]);
}
void build(int root ,int l,int r){
sum[root]=0;
lazy[root]=0;
if(l==r){
scanf("%d",&b[l]);
sub[root]=b[l];
return ;
}
int mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
up(root);
}
void down(int root){
lazy[root*2]+=lazy[root];
sub[root*2]-=lazy[root];
lazy[root*2+1]+=lazy[root];
sub[root*2+1]-=lazy[root];
lazy[root]=0;
}
void update1(int root,int l,int r){
if(l==r){
sum[root]++;
sub[root]=b[l];
return;
}
int mid=(l+r)/2;
down(root);
if(!sub[root*2]){
update1(root*2,l,mid);
}
if(!sub[root*2+1]){
update1(root*2+1,mid+1,r);
}
up(root);
}
void update(int root,int L,int R,int l,int r){
if(L>=l && R<=r){
lazy[root]++;
sub[root]--;
if(!sub[root]){
update1(root,L,R);
}
return;
}
int mid=(L+R)/2;
down(root);
if(l<=mid){
update(root*2,L,mid,l,r);
}
if(r>mid){
update(root*2+1,mid+1,R,l,r);
}
up(root);
}
int query(int root,int L,int R,int l,int r){
if(L>=l && R<=r){
return sum[root];
}
int ans=0;
int mid=(L+R)/2;
down(root);
if(l<=mid){
ans+=query(root*2,L,mid,l,r);
}
if(r>mid){
ans+=query(root*2+1,mid+1,R,l,r);
}
up(root);
return ans;
}
int main(){
int n,q;
while(~scanf("%d %d",&n,&q)){
build(1,1,n);
char s;
int a=0,b=0;
while(q--){
getchar();
scanf("%c",&s);
if(s=='a'){
scanf("%*c%*c %d %d",&a,&b);
update(1,1,n,a,b);
}
else if(s=='q'){
scanf("%*c%*c%*c%*c %d %d",&a,&b);
printf("%d\n",query(1,1,n,a,b));
}
}
}
}