题意:n个数,先给你一个集合b的值,集合a里的元素初始都为0。给你m个操作,add x y:表示a集合里x~y的值都加上1,query x y:表示计算ai/bi(i = x,x+1...y)的和,并输出。
这题多校赛的时候有一点想法,但是感觉很难实现,本来想的是能不能判断这段区间的最小值b是多少,如果总和的值大于最小值b则向下更新,但是感觉不好实现,看了大佬的题解,才知道他们是反过来做的。有时候思路不能太正着想,还是得反过来,有时候会发现很神奇的事情(说到底还是我菜啊)
思路:用线段树来做,设一个变量Min,初始Min为这个区间的最小的b,然后每一次更新区间都把最小值--,如果最小值等于0的时候则向下更新子节点,如果l == r的时候则num++,并且把Min重新设为b[l]。好多地方都有pushdown()和updown(),千万别漏了,漏了就凉凉了。
AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 1e5+10;
struct Node{
int Min, num;
}node[maxn<<2];
int add[maxn<<2],b[maxn];
int min(int a,int b){
return a<b?a:b;
}
void updown(int rt){
node[rt].num = node[rt<<1].num+node[rt<<1|1].num;
node[rt].Min = min(node[rt<<1].Min,node[rt<<1|1].Min);
}
void build(int l,int r,int rt){
add[rt] = 0;
if(l == r){
node[rt].Min = b[l];
node[rt].num = 0;
return;
}
int m = l+r>>1;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
updown(rt);
}
void pushdown(int rt,int l,int r){
if(add[rt]){
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
node[rt<<1].Min -= add[rt];
node[rt<<1|1].Min -= add[rt];
add[rt] = 0;
}
}
void change(int rt,int l,int r){ //如果存在Min等于0,则更新其子节点
if(l == r){ //当达到叶子节点的时候,就可以更新num值
node[rt].num++;
node[rt].Min = b[l];
return;
}
pushdown(rt, l, r);
int m = l+r>>1;
if(node[rt<<1].Min == 0)
change(rt<<1, l, m);
if(node[rt<<1|1].Min == 0)
change(rt<<1|1, m+1, r);
updown(rt);
}
void update(int L,int R,int l,int r,int rt){
if(node[rt].Min == 0){
change(rt, l, r);
}
if(L <= l && r <= R){
node[rt].Min--;
add[rt]++;
if(node[rt].Min == 0){
change(rt, l, r);
}
return;
}
pushdown(rt, l, r);
int m = l+r>>1;
if(L <= m)
update(L, R, l, m, rt<<1);
if(R > m)
update(L, R, m+1, r, rt<<1|1);
updown(rt);
}
int query(int L,int R,int l,int r,int rt){
if(node[rt].Min == 0){
change(rt,l,r);
}
if(L <= l&& r <= R){
return node[rt].num;
}
pushdown(rt,l,r);
int m = l+r>>1, ans = 0;
if(L <= m)
ans += query(L, R, l, m, rt<<1);
if(R > m)
ans += query(L, R, m+1, r, rt<<1|1);
updown(rt);
return ans;
}
int main(){
int n, m, x, y, i;
char ch[10];
while(scanf("%d%d",&n,&m)!=EOF){
for(i = 1; i <= n; i++){
scanf("%d",&b[i]);
}
build(1, n, 1);
while(m--){
scanf("%s%d%d",ch,&x,&y);
if(ch[0] == 'a')
update(x, y, 1, n, 1);
else
printf("%d\n",query(x, y, 1, n, 1));
}
}
return 0;
}