【题解】[HDU6315] Naive Operations【线段树 树状数组 调和级数】
题意
给定排列 \(b\),维护序列 \(a\):
- 区间 \(+1\);
- 求 \(\lfloor \dfrac{b_i}{a_i}\rfloor\) 的区间和。
\(n,m\leq 10^5\)
题解
用一棵线段树维护 \(b_i-(a_i\bmod b_i)\) 的区间最小值,每次修改会导致一些 \(\lfloor \dfrac{a_i}{b_i}\rfloor\ +1\),对于这些点,在树状数组上依次修改。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int b[N],n;
int t[N<<2],tag[N<<2],r[N];
int qry(int p){ int ans=0;for(;p;p-=(p&-p))ans+=r[p];return ans; }
void mdf(int p){ for(;p<=n;p+=(p&-p))r[p]++; }
void pushup(int x){ t[x]=max(t[x<<1],t[x<<1|1]); }
void pushdown(int x){
tag[x<<1]+=tag[x];
tag[x<<1|1]+=tag[x];
t[x<<1]+=tag[x];
t[x<<1|1]+=tag[x];
tag[x]=0;
}
void upd(int x,int nl,int nr){
if(nl==nr){
if(t[x]==0)t[x]=-b[nl],mdf(nl);
return;
}
pushdown(x);
int mid=nl+nr>>1;
while(t[x<<1]==0)upd(x<<1,nl,mid);
while(t[x<<1|1]==0)upd(x<<1|1,mid+1,nr);
pushup(x);
}
void modify(int l,int r,int x,int nl,int nr){
if(nr<l||nl>r)return;
if(l<=nl&&nr<=r){
tag[x]++;
t[x]++;
return;
}
pushdown(x);
int mid=nl+nr>>1;
modify(l,r,x<<1,nl,mid);
modify(l,r,x<<1|1,mid+1,nr);
pushup(x);
}
void build(int x,int l,int r){
if(l==r){
t[x]=-b[l];
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
}
char s[7];
int main(){
int q;
while(scanf("%d%d",&n,&q)!=EOF){
for(int i=1;i<=n;i++)scanf("%d",b+i);
memset(r,0,sizeof(r));
memset(t,0,sizeof(t));
memset(tag,0,sizeof(tag));
build(1,1,n);
while(q--){
int l,r;
scanf("%s%d%d",s,&l,&r);
if(s[0]=='a')
modify(l,r,1,1,n),upd(1,1,n);
else
printf("%d\n",qry(r)-qry(l-1));
}
}
return 0;
}