#6277. 数列分块入门 1
内存限制:256 MiB时间限制:100 ms标准输入输出
题目描述
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。
输入格式
第一行输入一个数字 n。
第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。
接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。
若 opt=0,表示将位于 [l,r] 的之间的数字都加 c。
若 opt=1,表示询问 ar 的值(l 和 c 忽略)。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例输入
4 1 2 2 3 0 1 3 1 1 0 1 0 0 1 2 2 1 0 2 0
样例输出
2 5
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e5+10;
const int INF = 1e8+10;
inline int read()
{
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while('0' <= ch && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int n,a[maxn],tag[maxn],belong[maxn],l[maxn],r[maxn];
int block, num;
void build()
{
block = 0.5 * sqrt(n); //0.5比较快
num = n / block; if(n % block) num++;
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = i * block;
r[num] = n;
for(int i = 1; i <= n; i++)
belong[i] = (i - 1) / block + 1;
}
void update(int x, int y, int c)
{
int t1 = belong[x], t2 = belong[y];
for(int i = x; i <= min(r[t1], y); i++)//对左区间
//对第一个不完整区间暴力加法,分为t1==t2||t1!=t2,就是两种合在一起,所以有了min
a[i] += c;
if(t1 != t2) for(int i = l[t2]; i <= y; i++)//对右区间
a[i] += c;
for(int i = t1 + 1; i < t2; i++) tag[i] += c;//块内的
}
int main()
{
n = read();
build();
for(int i = 1; i <= n; i++)
{
int opt = read(), l = read(), r = read(), c = read();
if(opt == 0) update(l,r,c);
else printf("%d\n",a[r]+tag[belong[r]]);
}
return 0;
}