题目描述 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\n",Query(u,v));
56 }
57 return 0;
58 }
来源:https://www.cnblogs.com/Shy-key/p/7218055.html