题目意思
初始a数组为0,给你一个b数组,q次询问add x y为a数组区间x y增加1,query x y查询区间x~y中a[i]/b[i]向下取正的和值。
解题思路
区间查询问题,我们首先想到的就是线段树。
我们用sum数组去维护区间的和值,由于分母是固定的,那么就维护一个数组sub[root]=min(b[i]-a[i]%b[i])的值。这样如果sub[root]=0,那么我们就下推懒惰标记,同时更新区间的值。
代码部分
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <algorithm>
#define lchild left,mid,root<<1
#define rchild mid+1,right,root<<1|1
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int b[maxn];
int sub[maxn<<2],sum[maxn<<2],lazy[maxn<<2];
///更新线段树节点
void push_up(int root)
{
sum[root]=sum[root<<1]+sum[root<<1|1];
sub[root]=min(sub[root<<1],sub[root<<1|1]);
}
///懒惰标记下推
void push_down(int root)
{
lazy[root<<1]+=lazy[root];
sub[root<<1]-=lazy[root];
lazy[root<<1|1]+=lazy[root];
sub[root<<1|1]-=lazy[root];
lazy[root]=0;
}
///构建线段树
void build(int left,int right,int root)
{
sum[root]=0;
lazy[root]=0;
if(left==right)
{
scanf("%d",&b[left]);
sub[root]=b[left];
return;
}
int mid=(left+right)>>1;
build(lchild);
build(rchild);
push_up(root);
}
void update1(int left,int right,int root)
{
if(left==right)
{
sum[root]++;
sub[root]=b[left];
return ;
}
int mid=(left+right)>>1;
push_down(root);
if(!sub[root<<1])
update1(lchild);
if(!sub[root<<1|1])
update1(rchild);
push_up(root);
}
///更新操作
void update(int a,int b,int left,int right,int root)
{
if(left>=a&&right<=b)
{
lazy[root]++;
sub[root]--;
if(!sub[root])
update1(left,right,root);
return;
}
int mid=(left+right)>>1;
push_down(root);
if(a<=mid)
update(a,b,lchild);
if(b>mid)
update(a,b,rchild);
push_up(root);
}
///查询操作
int query(int a,int b,int left,int right,int root)
{
if(left>=a&&right<=b)
{
return sum[root];
}
int ans=0;
int mid=(left+right)>>1;
push_down(root);
if(a<=mid)
ans+=query(a,b,lchild);
if(b>mid)
ans+=query(a,b,rchild);
push_up(root);
return ans;
}
int main()
{
int n,q;
while(scanf("%d%d",&n,&q)!=EOF)
{
build(1,n,1);
char s[10];
int a,b;
while(q--)
{
scanf("%s%d%d",s,&a,&b);
if(s[0]=='a')
update(a,b,1,n,1);
else
printf("%d\n",query(a,b,1,n,1));
}
}
return 0;
}