LOJ #6277. 数列分块入门 1-分块(区间加法、单点查询)
题目描述
给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,单点查值。
输入格式
第一行输入一个数字 nn。
第二行输入 nn 个数字,第 ii 个数字为 a_iai,以空格隔开。
接下来输入 nn 行询问,每行输入四个数字 \mathrm{opt}opt、ll、rr、cc,以空格隔开。
若 \mathrm{opt} = 0opt=0,表示将位于 [l, r][l,r] 的之间的数字都加 cc。
若 \mathrm{opt} = 1opt=1,表示询问 a_rar 的值(ll 和 cc 忽略)。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0
样例输出
2
5
数据范围与提示
对于 100\%100% 的数据,1 \leq n \leq 50000, -2^{31} \leq \mathrm{others}1≤n≤50000,−231≤others、\mathrm{ans} \leq 2^{31}-1ans≤231−1。
代码:
1 //#6277. 数列分块入门 1-区间加法,单点查询 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 const int maxn=5e4+10; 6 7 int n,m,pos[maxn]; 8 int a[maxn],tag[maxn]; 9 10 void update(int l,int r,int c) 11 { 12 if(pos[l]==pos[r]){//如果在一个块内,直接遍历更新 13 for(int i=l;i<=r;i++) 14 a[i]+=c; 15 } 16 else{//如果不在同一个块内 17 for(int i=l;i<=pos[l]*m;i++)//遍历更新完整块左边的部分 18 a[i]+=c; 19 for(int i=pos[l]+1;i<=pos[r]-1;i++)//更新完整的块 20 tag[i]+=c; 21 for(int i=(pos[r]-1)*m+1;i<=r;i++)//更新完整块右边的部分 22 a[i]+=c; 23 } 24 } 25 26 int main() 27 { 28 int n; 29 scanf("%d",&n); 30 m=sqrt(n); 31 for(int i=1;i<=n;i++) 32 scanf("%d",&a[i]); 33 for(int i=1;i<=n;i++) 34 pos[i]=(i-1)/m+1;//块号 35 for(int i=1;i<=n;i++){ 36 int op,l,r,c; 37 scanf("%d%d%d%d",&op,&l,&r,&c); 38 if(op==0) update(l,r,c); 39 else printf("%d\n",tag[pos[r]]+a[r]); 40 } 41 return 0; 42 }