块的操作主要有:
block是块的大小
t是块的数量
st是每个块的开始的下标
ed是每个块的结束的下标
pos是每个元素对应块的下标
sum是对应块的元素的和
add是增量标记 用于区间修改+区间查询
const int MAX=10010; int n; int a[MAX]; int st[MAX],ed[MAX]; int pos[MAX]; int sum[MAX]; int add[MAX]; //区间修改 void change(int l,int r,int d){ int p=pos[l]; int q=pos[r]; if(p==q){ //情况1 区间位于一个块里面 for(int i=l;i<=r;i++){ a[i]+=d; } sum[p]+=d*(r-l+1); } else { //区间跨多个块 for(int i=p+1;i<=q-1;i++){ add[i]+=d; //完整的块里面的数据直接加上d } for(int i=l;i<=ed[p];i++){ //整块前面的散块 a[i]+=d; } sum[p]+=d*(ed[p]-l+1); for(int i=st[q];i<=r;i++){ //整块后面的散块 a[i]+=d; } sum[q]+=d*(p-st[q]+1); } } ll query(int l,int r){ int p=pos[l]; int q=pos[r]; ll ans=0; if(p==q){ //整块 for(int i=l;i<=r;i++){ ans+=a[i]; } ans+=add[p]*(r-l+1); } else { //有散块 for(int i=p+1;i<=q-1;i++){ ans+=sum[i]+add[i]*(ed[i]-st[i]+1); //先处理整块 } for(int i=l;i<=ed[p];i++){ //整合散块 ans+=a[i]; } ans+=add[p]*(ed[p]-l+1); for(int i=st[q];i<=r;i++){ ans+=a[i]; } ans+=add[q]*(r-st[q]+1); } return ans; } int main(){ int block=sqrt(n); int t=n/block; if(n%block) t++; for(int i=1;i<=n;i++){ st[i]=(i-1)*block+1; ed[i]=i*block; } ed[t]=n; for(int i=1;i<=n;i++){ pos[i]=(i-1)/block+1; //pos是第i个元素所在的块 } for(int i=1;i<=t;i++){ for(int j=st[i];j<=ed[i];j++){ sum[i]+=a[j]; //sum是第i块的区间和 } } }