题目描述 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
1 #include <cstdio> 2 #include <cmath> 3 4 using namespace std; 5 6 #define LL long long 7 const int N(500); 8 LL n,q,num[N*N],u,v,x,op; 9 10 LL C,cnt,str[N],ove[N],bel[N*N],sum[N],tag[N]; 11 #define min(a,b) (a<b?a:b) 12 #define max(a,b) (a>b?a:b) 13 void Build() 14 { 15 C=sqrt(n); 16 for(LL i=1;i<=n;i+=C) 17 { 18 str[++cnt]=i; 19 ove[cnt]=min(n,i+C-1); 20 } 21 for(LL i=1;i<=cnt;i++) 22 for(LL j=str[i];j<=ove[i];j++) 23 bel[j]=i,sum[i]+=num[j]; 24 } 25 void Update(LL u,LL v,LL x) 26 { 27 for(LL i=bel[u];i<=bel[v];i++) 28 if(str[i]>=u&&ove[i]<=v) tag[i]+=x,sum[i]+=(ove[i]-str[i]+1)*x; 29 else for(LL j=max(str[i],u);j<=min(ove[i],v);j++) num[j]+=x,sum[i]+=x; 30 } 31 LL Query(LL u,LL v) 32 { 33 LL ret=0; 34 for(LL i=bel[u];i<=bel[v];i++) 35 if(str[i]>=u&&ove[i]<=v) ret+=sum[i]; 36 else for(LL j=max(str[i],u);j<=min(ove[i],v);j++) ret+=num[j]+tag[i]; 37 return ret; 38 } 39 40 int main() 41 { 42 scanf("%lld",&n); 43 for(LL i=1;i<=n;i++) 44 scanf("%lld",num+i); 45 Build(); 46 scanf("%lld",&q); 47 for(;q--;) 48 { 49 scanf("%lld%lld%lld",&op,&u,&v); 50 if(op==1) 51 { 52 scanf("%lld",&x); 53 Update(u,v,x); 54 } 55 else printf("%lld ",Query(u,v)); 56 } 57 return 0; 58 }