洛谷P3372 【模板】线段树 1

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和

输入输出格式

输入格式:

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

输出格式:

输出包含若干行整数,即为所有操作2的结果。

输入输出样例

输入样例#1: 
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出样例#1: 
11
8
20

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^,保证在int64/long long数据范围内)

样例说明:

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 using namespace std;
 5 ll read()
 6 {
 7     ll x=0,f=1;
 8     char ch=getchar();
 9     while(ch<'0'||ch>'9')
10     {
11         if(ch=='-')
12             f=-1;
13         ch=getchar();
14     }
15     while(ch>='0'&&ch<='9')
16     {
17         x=x*10+ch-'0';
18         ch=getchar();
19     }
20     return x*f;
21 }
22 ll n,m,a,b,t,x,y,z;
23 ll tree[100005],tree1[100005];
24 void add(ll*z,ll x,ll num)
25 {
26     while(x<=n)
27     {
28         z[x]+=num;
29         x+=x&(-x);
30     }
31 }
32 ll getsum(ll*z,ll x)
33 {
34     ll sum=0;
35     while(x>0)
36     {
37         sum+=z[x];
38         x-=x&(-x);
39     }
40     return sum;
41 }
42 int main()
43 {
44     n=read(),m=read();
45     for(ll i=1; i<=n; i++)
46     {
47         a=read();
48         b=a-b;
49         add(tree,i,b);
50         add(tree1,i,(i-1)*b);
51         b=a;
52     }
53     for(ll i=1; i<=m; i++)
54     {
55         t=read();
56         if (t==1)
57         {
58             x=read(),y=read(),z=read();
59             add(tree,x,z);
60             add(tree,y+1,-z);
61             add(tree1,x,z*(x-1));
62             add(tree1,y+1,-z*y);
63         }
64         else
65         {
66             x=read(),y=read();
67             printf("%lld\n",(y*getsum(tree,y)-(x-1)*getsum(tree,x-1))-(getsum(tree1,y)-getsum(tree1,x-1)));
68         }
69     }
70     return 0;
71 }
View Code

 

posted @ 2018-12-30 10:32  ~liweilin~  阅读(164)  评论(0编辑  收藏  举报