首页 > 编程语言 > 详细

树状数组--模版

时间:2020-01-16 09:56:35      阅读:83      评论:0      收藏:0      [点我收藏+]

题目描述

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

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

 

树状数组--模版

原文:https://www.cnblogs.com/very-beginning/p/12199592.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!