您的位置:首页 > 其它

CodeVS 1080 线段树练习 分块 块状数组

2016-02-02 10:27 363 查看

题意

给定序列a,支持两种操作:

1. 单点修改

2. 区间求和

1≤N≤1000001\leq N\leq 100000

M≤10000M\leq 10000

分析

考虑分块。

我们把连续的n√\sqrt n个元素放在一块,并保存所有值的和。

对于单点修改,找到对应块,修改对应点的值和块的和。

对于区间求和,注意分类讨论:

①当l,rl,r在同一块时,直接求和;

②当l,rl,r不在同一块时,

需要统计三种:ll到块尾,块头到rr,ll的下一块到rr的上一块的和。

还有注意要开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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: