COdeVS——T 1082 线段树练习 3 (分块练习)

偶尔善良 提交于 2020-03-30 09:20:42
 空间限制: 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

 

 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 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!