题意:
有一个a[1--n]和b[1--n]的数组,a初始化为0,b初始化如第二行输入,接下来有m个操作;
操作类型如下:
“add l r” -- a数组在[ l , r ]区间全部加1;
“query l r” -- 计算在[ l , r ]区间所有ai/bi的和。
题解:
线段树模板
ai/bi可以看作ai是bi的倍数,那么我们可以设一个值为bi,维护的时候把它减一,如果值为0,则用一个sum来记录0的个数就是ai/bi;
线段树用lazy来缩短区间更新的时间,如果区间里的最小值minn--bi是1,一定要再往下更新,因为下层到达1的个数是不确定的。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 100010;
struct node{
int minn, sum_0, lazy, v;
}tree[maxn << 2];
int b[maxn], n;
void pushdown(int root, int l, int r){
tree[root << 1].lazy += tree[root].lazy;
tree[root << 1 | 1].lazy += tree[root].lazy;
tree[root << 1].minn -= tree[root].lazy;
tree[root << 1 | 1].minn -= tree[root].lazy;
tree[root].lazy = 0;
}
void pushup(int root, int l, int r){
tree[root].sum_0 = tree[root << 1 | 1].sum_0 + tree[root << 1].sum_0;
tree[root].minn = min(tree[root << 1].minn, tree[root << 1 | 1].minn);
}
void build(int root, int l, int r){
int mid = (l+r) >> 1;
tree[root].lazy = tree[root].sum_0 = 0;
if(l == r){
tree[root].minn = tree[root].v = b[l];
tree[root].sum_0 = 0;
return;
}
build(root << 1, l, mid);
build(root << 1 | 1, mid+1, r);
pushup(root, l, r);
}
//区间更新
void add(int root, int l, int r, int ql, int qr){
int mid = (l+r) >> 1;
if(l > r){
return;
}
if(tree[root].minn > 1 && l == ql && r == qr){
tree[root].lazy++;
tree[root].minn--;
return;
}
if(l == r && tree[root].minn == 1){
tree[root].sum_0++;
tree[root].minn = tree[root].v;
tree[root].lazy = 0;
return;
}
if(tree[root].lazy){
pushdown(root, l, r);
}
if(qr <= mid){
add(root << 1, l, mid, ql, qr);
}
else if(ql > mid){
add(root << 1 | 1, mid+1, r, ql, qr);
}
else{
add(root << 1, l, mid, ql, mid);
add(root << 1 | 1, mid+1, r, mid+1, qr);
}
pushup(root, l, r);
}
//区间查询
int query(int root, int l, int r, int ql, int qr){
int mid = (l+r) >> 1;
if(l > r){
return 0;
}
if(l == ql && r == qr){
return tree[root].sum_0;
}
if(qr <= mid){
return query(root << 1, l, mid, ql, qr);
}
else if(ql > mid){
return query(root << 1 | 1, mid+1, r, ql, qr);
}
else{
return query(root << 1, l, mid, ql, mid) + query(root << 1 | 1, mid+1, r, mid+1, qr);
}
}
int main(){
int m;
while(~scanf("%d %d", &n, &m)){
for(int i = 1; i <= n; i++){
scanf("%d", &b[i]);
}
build(1, 1, n);
for(int i = 0; i < m; i++){
char ss[10];
int s, e;
scanf("%s %d %d", ss, &s, &e);
if(ss[0] == 'a'){
add(1, 1, n, s, e);
}
else{
printf("%d\n", query(1, 1, n, s, e));
}
}
}
}