首页 > 代码库 > codevs 1082 线段树练习 3 --分块练习

codevs 1082 线段树练习 3 --分块练习

时间限制: 3 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
题目描述 Description

给你N个数,有两种操作:


1:给区间[a,b]的所有数增加X


2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,

 

再接下来一个正整数Q,每行表示操作的个数,

 

如果第一个数是1,后接3个正整数,

 

表示在区间[a,b]内每个数增加X,如果是2,

 

表示操作2询问区间[a,b]的和是多少。

 

pascal选手请不要使用readln读入

输出描述 Output Description

对于每个询问输出一行一个答案

样例输入 Sample Input

3

1

2

3

2

1 2 3 2

2 2 3

样例输出 Sample Output

9

数据范围及提示 Data Size & Hint

数据范围

1<=n<=200000

1<=q<=200000

 
分块大法 此题用分块优于线段树
屠龙宝刀点击就送
#include <ctype.h>#include <cstdio>#include <cmath>#define N 500typedef long long LL;void read(LL &x){    x=0;bool f=0;char ch=getchar();    while(!isdigit(ch))    {        if(ch==-) f=1;        ch=getchar();    }    while(isdigit(ch))    {        x=x*10+ch-0;        ch=getchar();    }    x=f?(~x)+1:x;}LL C,m,belong[N*N],cnt,tag[N],sum[N],beg[N],en[N],n,a[N*N]; LL min(LL a,LL b) {return a>b?b:a;}LL max(LL a,LL b) {return a>b?a:b;} void update(LL x,LL y,LL z){    for(LL i=belong[x];i<=belong[y];i++)    {        if(x<=beg[i]&&y>=en[i]) tag[i]+=z,sum[i]+=(en[i]-beg[i]+1)*z;        else for(LL j=max(beg[i],x);j<=min(en[i],y);j++) a[j]+=z,sum[i]+=z;    }}LL query(LL x,LL y){    LL ans=0;    for(LL i=belong[x];i<=belong[y];i++)    {        if(x<=beg[i]&&y>=en[i]) ans+=sum[i];        else for(LL j=max(beg[i],x);j<=min(en[i],y);j++) ans+=a[j]+tag[i];    }    return ans;}int main(){    read(n);    for(LL i=1;i<=n;i++) read(a[i]);    C=sqrt(n);    for(LL i=1;i<=n;i+=C)    {        beg[++cnt]=i;        en[cnt]=min(i+C-1,n);    }    for(LL i=1;i<=cnt;i++)    {        for(LL j=beg[i];j<=en[i];j++) belong[j]=i,sum[i]+=a[j];    }    read(m);    for(LL type,x,y,z;m--;)    {        read(type);        read(x);        read(y);        if(type==1)        {            read(z);            update(x,y,z);        }        else printf("%lld\n",query(x,y));    }    return 0;}

 

codevs 1082 线段树练习 3 --分块练习