您的位置:首页 > 其它

(树状数组)hdu1166 敌兵布阵

2017-08-07 20:40 169 查看
今天学习了树状数组,看了能解决的问题之后觉得跟线段树非常像,不过后来了解到线段树的用途其实很广泛,如单点更新、区间更新、区间查询、最值查询等问题,都能够高效的解决。而树状数组则是一种空间占用率很低、且算法效率高(O(logn))的一种数据结构。并且,代码很简洁,只用短短几行代码便完成了所有的操作。

首先是lowbit操作——树状数组的核心。这个操作的作用是把一个二进制数变为只保留最低位的1后形成的数,如110010——变成10。实现方法是,由计算机补码运算的原理,对一个数取相反数相当于逐位取反再加1,再用这个数本身和他的相反数做逐位与(&)操作,即得到最后一位1,具体代码如下:

int lowbit(int k) {//树状数组基本操作,取一个数(二进制)最低位的1
return k & (-k);//(由计算机补码原理,一个数取负相当于这个数逐位取反再加1
}


以下是更新、求和操作:

单点更新:

void update(int pos, int num) {//从pos到n,更新节点的值
while(pos <= n) {
a[pos] += num;//更新
pos += lowbit(pos);//向上更新受到影响的祖先结点
}
return;
}


求和:
int sum(int end) {//求一段区间的和
int sum = 0;
while(end > 0) {
sum += a[end];
end -= lowbit(end);
}
return sum;
}
有了这些基本操作之后,用这道题,hdu1166——敌兵布阵,练了一下手。昨天用线段树做出了它,现在改用树状数组实现,代码简洁易懂。

题意:一个数组a
,有如下三个操作:

(1) Add i j,i和j为正整数,表示第i个数增加j

(2)Sub i j ,i和j为正整数,表示第i个数减少j(j不超过30);

(3)Query i j ,i和j为正整数,i<=j,表示询问ai到aj的和;

简单的树状数组应用,加减操作可以通过单点更新来实现,查询区间和可由sum(b)-sum(a-1)得到。具体代码如下:

#include<bits/stdc++.h>
typedef long long ll;

const int maxn = 50010;

int t, n;
int a[maxn];

int lowbit(int k) {//树状数组基本操作,取一个数(二进制)最低位的1 return k & (-k);//(由计算机补码原理,一个数取负相当于这个数逐位取反再加1 }

void update(int pos, int num) {//从pos到n,更新节点的值 while(pos <= n) { a[pos] += num;//更新 pos += lowbit(pos);//向上更新受到影响的祖先结点 } return; }

int sum(int end) {//求一段区间的和
int sum = 0;
while(end > 0) {
sum += a[end];
end -= lowbit(end);
}
return sum;
}

int main() {
while(~scanf("%d", &t)) {
for(int cas = 1;cas <= t;cas++) {
scanf("%d", &n);
int m;
memset(a, 0, sizeof(a));
for(int i = 1;i <= n;i++) {
scanf("%d", &m);
update(i, m);//每输一个数,更新一次,建立树状数组
}
char str[10];
printf("Case %d:\n", cas);
while(scanf("%s", str), strcmp(str, "End")) {
int a1, a2;
if(strcmp(str, "Add") == 0) {
scanf("%d %d", &a1, &a2);
update(a1, a2);//向上更新
}
else if(strcmp(str, "Sub") == 0) {
scanf("%d %d", &a1, &a2);
update(a1, -a2);//向上更新
}
else if(strcmp(str, "Query") == 0) {
scanf("%d %d", &a1, &a2);
printf("%d\n", sum(a2) - sum(a1-1));//b到a-1即为a到b段的和
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: