题目描述
如题,已知一个数列,你需要进行下面两种操作:
将某一个数加上 x
求出某区间每一个数的和
输入格式
第一行包含两个正整数 n,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i项的初始值。
接下来 m 行每行包含 3 个整数,表示一个操作,具体如下:
1 x k 含义:将第 x 个数加上 k
2 x y 含义:输出区间 [x,y]内每个数的和
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
令这棵树的结点编号为C1,C2...Cn。令每个结点的值为这棵树的值的总和,那么容易发现:
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
...
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
这里有一个有趣的性质:
设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,
所以很明显:Cn = A(n – 2^k + 1) + ... + An
1 #include <cstdio>
2 #include <iostream>
3 using namespace std;
4 int n,m;
5 int x,y;
6 int w1;
7 int a[500001];
8 int s[500001];
9 void fix(int x,int v)
10 {
11 for (int i = x;i <= n;i+=i&-i)
12 {
13 s[i]+=v;
14 }
15 }
16 int find(int x)
17 {
18 int ret=0;
19 for (int i = x;i>0;i-=i&-i)
20 {
21 ret+=s[i];
22
23 }
24 return ret;
25 }
26 int main()
27 {
28 scanf ("%d%d",&n,&m);
29 for (int i = 1;i <= n;i++)
30 {
31 scanf ("%d",&a[i]);
32 fix(i,a[i]);
33 }
34 for (int i = 1;i <= m;i++)
35 {
36 scanf ("%d",&w1);scanf ("%d%d",&x,&y);
37 if (w1==1){
38 fix(x,y);
39 }
40 if (w1==2)
41 {
42 cout<<find(y)-find(x-1)<<endl;
43 }
44 }
45 return 0;
46 }
2.模版2
题目描述
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数数加上x
2.求出某一个数的值
输入格式
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含2或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k
操作2: 格式:2 x 含义:输出第x个数的值
输出格式
输出包含若干行整数,即为所有操作2的结果。
因为本题不是单纯修改一个数,而是修改一段区间的数,所以fix(x,k)表示把x到最后一个数都加上,但是我们把y+1到最后一个数也都加上了k,而我们只需要把x到y加k,所以fix(y+1,-k)把y+1到最后一个数都减去k,就是把多加的都减去。我们就知道了每个数所对应的修改量,把原来的数加上修改量,就是所得的数
1 #include <cstdio>
2 #include <iostream>
3 using namespace std;
4 long long n,m;
5 long long x,y,k;
6 long long w1;
7 long long a[500001];
8 long long s[500001];
9 void fix(long long x,long long v)
10 {
11 for (long long i = x;i <= n;i+=i&-i)
12 {
13 s[i]+=v;
14 }
15 }
16 long long find(long long x)
17 {
18 long long ret=0;
19 for (long long i = x;i>0;i-=i&-i)
20 {
21 ret+=s[i];
22 }
23 return ret;
24 }
25 int main()
26 {
27 scanf ("%lld%lld",&n,&m);
28 for (int i = 1;i <= n;i++)
29 {
30 scanf ("%lld",&a[i]);
31 }
32 for (int i = 1;i <= m;i++)
33 {
34 scanf ("%lld",&w1);
35 if (w1==1){
36 scanf ("%lld%lld%lld",&x,&y,&k);
37 fix(x,k);
38 fix(y+1,-k);
39 }
40 if (w1==2)
41 {
42 scanf ("%lld",&x);
43 cout<<a[x]+find(x)<<endl;
44 }
45 }
46 return 0;
47 }