我是靠谱客的博主 知性仙人掌,这篇文章主要介绍HDU-1166 敌兵布阵(树状数组详解),现在分享给大家,希望可以做个参考。

树状数组和线段树的区别:

树状数组可以解决的问题都可以用线段树解决,这两者的区别在于树状数组的系数要少很多,就比如字符串模拟大数可以解决大数问题,也可以解决1+1的问题,但没人会在1+1的问题上用大数模拟。

树状数组的优点和缺点:
树状数组的优点是修改和查询的复杂度都是O(logN),而且相比线段树系数要少很多,比传统数组要快,而且容易写。
缺点是遇到复杂的区间问题还是不能解决,功能还是有限。

树状数组的介绍:在这里插入图片描述

Tree[1] = A[1];
Tree[2] = A[1] + A[2];
Tree[3] = A[3];
Tree[4] = A[1] + A[2] + A[3] + A[4];
Tree[5] = A[5];
Tree[6] = A[5] + A[6];
Tree[7] = A[7];
Tree[8] = A[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8];

可以发现,这颗树是有规律的

Tree[i] = A[i - 2^k +1] + A[i - 2 ^ k+2] + … + A[i]; //k为i的二进制中从最低位到高位连续零的长度
例如8的二进制为1000,因此k为3,Tree[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8]

如果要实现求和,例如求前7项的和,SUM(7)=Tree[7]+Tree[6]+Tree[4]
可以得到SUMi = Tree[i] + Tree[i-2k1] + Tree[(i - 2k1) - 2k2] + …;
而2^k=(i)&(-i),通常叫做lowbit函数

复制代码
1
2
3
4
5
int lowbit(int x) { return x&(-x); }

lowbit(x)是x的二进制表达式中最低位的1所对应的值。

比如,6的二进制是110,所以lowbit(6)=2。

此时,就可以来构造树状数组

区间更新:

复制代码
1
2
3
4
5
6
7
8
9
void update(int i,int k)//在i位置加上k { while(i<=n) { tree[i]+=k; i+=lowbit(i); } }

求和:

复制代码
1
2
3
4
5
6
7
8
9
10
11
int getsum(int i)//求A[1 - i]的和 { int sum=0; while(i>0) { sum+=tree[i]; i-=lowbit(i); } return sum; }

下面是一道树状数组模板题
敌兵布阵

代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream> using namespace std; #include <cstring> int n,m; int a[50005],tree[50005];//原数组和树状数组 int lowbit(int x) { return x&(-x); } void update(int i,int k)//在i位置加上k { while(i<=n) { tree[i]+=k; i+=lowbit(i); } } int getsum(int i)//求A[1 - i]的和 { int sum=0; while(i>0) { sum+=tree[i]; i-=lowbit(i); } return sum; } int main() { int t; cin>>t; int s=1; while(t--) { cout<<"Case "<<s<<":"<<endl; s++; memset(a,0,sizeof(a)); memset(tree,0,sizeof(tree)); cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; update(i,a[i]);//输入初值的时候,也相当于更新了值 } string s; int a,b; while(cin>>s&&s!="End") { cin>>a>>b; if(s=="Query")//求和操作 { int sum = getsum(b) - getsum(a-1); //a-b区间和也就等于1-b区间和减去1-(a-1)区间和 cout << sum << endl; } else if(s=="Add")//加法 { update(a,b); } else if(s=="Sub") { update(a,-b); //减法,即为加上相反数 } } } return 0; }

最后

以上就是知性仙人掌最近收集整理的关于HDU-1166 敌兵布阵(树状数组详解)的全部内容,更多相关HDU-1166内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(69)

评论列表共有 0 条评论

立即
投稿
返回
顶部