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

来源:互联网 发布:4g网络哪家有 编辑:程序博客网 时间:2024/06/07 02:03

题意

给定序列a,支持两种操作:
1. 单点修改
2. 区间求和

1N100000
M10000

分析

考虑分块。
我们把连续的n个元素放在一块,并保存所有值的和。

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

对于区间求和,注意分类讨论:
①当l,r在同一块时,直接求和;
②当l,r不在同一块时,
需要统计三种:l到块尾,块头到rl的下一块到r的上一块的和。

还有注意要开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;}
0 0
原创粉丝点击