题目大意
给出长度为 n n n的原序列,有 n n n个操作,操作有两种:
- 给 l ∼ r l \sim r l∼r这个区间每个数加上 c c c
- 查询 a r a_r ar的值
题目分析
应该是分块的一种比较低幼的题,虽说是分块模板,可是若有神犇用线段数做也未尝不可——(虽然本蒟是老老实实用分块做的……)
预处理:开一个
b
l
o
blo
blo数组,
b
l
o
i
blo_i
bloi表示
i
i
i属于第几个块。每个块长度为
n
\sqrt {n}
n,共分成
n
\sqrt {n}
n块,在大部分情况下,最右边应该会留下一个不完整的块。
对于每次修改,把
[
l
,
r
]
[l,r]
[l,r]这个区间内的完整块直接打上标记,不完整部分直接暴力乱搞(每个不完整部分长度不会超过
n
\sqrt{n}
n,对时间复杂度不会产生大的影响)
查询的时候直接用
a
r
a_r
ar的值加上被标记的值就好了。
C o d e Code Code
#include<iostream>
#include<cstdio>
#include<cmath>
#define sco 50010
using namespace std;
int a[sco],blo[sco],lz[sco],sq,n;
inline void add(int l,int r,int c){
int x=min(r,blo[l]*sq);
for(int i=l;i<=x;++i){
a[i]+=c;
}
if(blo[l]==blo[r])return;
x=(blo[r]-1)*sq+1;
for(int i=x;i<=r;++i){
a[i]+=c;
}
for(int i=blo[l]+1;i<=blo[r]-1;++i){
lz[i]+=c;
}
}
int main(){
scanf("%d",&n);sq=sqrt(n);
for(int i=1;i<=n;++i){
scanf("%d",a+i);
blo[i]=(i-1)/sq+1;
}
for(int i=1;i<=n;++i){
int l,r,c,opt;
scanf("%d%d%d%d",&opt,&l,&r,&c);
if(opt==0) add(l,r,c);
if(opt==1) printf("%d\n",a[r]+lz[blo[r]]);
}
return 0;
}