题意
给定序列a,支持两种操作:
1. 单点修改
2. 区间求和
1≤N≤100000
M≤10000
分析
考虑分块。
我们把连续的
n√
个元素放在一块,并保存所有值的和。
对于单点修改,找到对应块,修改对应点的值和块的和。
对于区间求和,注意分类讨论:
①当
l,r
在同一块时,直接求和;
②当
l,r
不在同一块时,
需要统计三种:
l
到块尾,块头到
还有注意要开long long。
代码
#include <cstdio>
#include <cctype>
#include <cmath>
typedef long long Lint;
const int N=100010;
const int U=400;
int n;
int unit;
struct Block
{
int a[U];
Lint sum;
}b[U];
int btot;
inline int read(void)
{
int x=0,f=1; char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
int m;
inline void update(int loc,int add)
{
int lb=(loc-1)/unit+1,lc=loc-(lb-1)*unit;
b[lb].a[lc]+=add;
b[lb].sum+=add;
}
Lint query(int l,int r)
{
int lb=(l-1)/unit+1,lc=l-(lb-1)*unit;
int rb=(r-1)/unit+1,rc=r-(rb-1)*unit;
Lint sum=0;
if (lb==rb)
for (int i=lc;i<=rc;i++)
sum+=b[lb].a[i];
else
{
for (int i=lc;i<=unit;i++) sum+=b[lb].a[i];
for (int i=lb+1;i<=rb-1;i++) sum+=b[i].sum;
for (int i=1;i<=rc;i++) sum+=b[rb].a[i];
}
return sum;
}
int main(void)
{
n=read();
unit=(int)sqrt(n);
int nowcur=unit; int x;
for (int i=1;i<=n;i++)
{
if (nowcur==unit)
btot++,nowcur=0;
x=read();
b[btot].sum+=x;
b[btot].a[++nowcur]=x;
}
int k,y,z; m=read();
for (int i=1;i<=m;i++)
{
k=read(),y=read(),z=read();
if (k==1)
update(y,z);
else printf("%d\n",query(y,z));
}
return 0;
}