树状数组--模版1和2 P3368、P3374

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

将某一个数加上 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 }

 

posted @ 2020-01-16 09:08  小又又  阅读(169)  评论(0)    收藏  举报