题目【模板】树状数组1:https://www.luogu.com.cn/problem/P3374
树状数组和线段树差不多,可以处理区间操作,但是处理不了太复杂的区间问题。,不过代码比线段树简洁很多很多!!!时间复杂度都为O(logn)。
例如,区间[1,8]存储方式如下:
1 tree[1]=num[1];//001---001 2 tree[2]=num[2]+num[1];//010---010 001 3 tree[3]=num[3];//011---011 4 tree[4]=num[4]+num[3]+num[2]+num[1];//100---100 011 010 001 5 tree[5]=num[5];//101---101 6 tree[6]=num[6]+num[5];//110---110 101 7 tree[7]=num[7];//111---111 8 tree[8]=num[8]+num[7]+num[6]+num[5]+num[4]+num[3]+num[2]+num[1];///1000---1000 0111 0110 0101 0100 0011 0010 0001
从注释可以看出存储方式和二进制有关系。
递推可得,当第x个数加上k时,tree[x]要加k,然后tree[x+x只剩最低位的1]也要加上x,循环往复。
根据负数在计算机中用补码存储可得k & -k即为x只剩最低位的1。
如7&-7
7用二进制表示为111,-7补码形式为001,111&001得001,所以7只剩最低位的1为001.
AC代码:
#include<iostream> #include<stdio.h> #include<algorithm> #define maxn 500010 typedef long long ll; using namespace std; int n; ll tree[maxn << 2]; int lowbit(int k) { return k & -k; } void add(int x, ll k) { while (x <= n) { tree[x] += k; x += lowbit(x); } } ll sum(int x) { ll ans = 0; while (x != 0) { ans += tree[x]; x -= lowbit(x); } return ans; } int main() { int m, k, x, y; ll a; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%lld", &a); add(i,a); } while (m--) { cin >> k; if (k == 1) { scanf("%d%lld", &x, &a); add(x,a); } else { scanf("%d%d", &x, &y); if (x <= y) cout << sum(y)-sum(x-1)<< endl; } } return 0; }
O(∩_∩)O哈哈~
补充一道区间加k的操作。
用差分思想和树状数组结合。
设数组a[]={1,6,8,5,10},那么差分数组b[]={1,5,2,-3,5}
也就是说b[i]=a[i]-a[i-1];(a[0]=0;),则递推可得:a[i]=b[1]+....+b[i]
所以对区间[x,y]进行修改,只用修改b[x]与b[y+1]:
b[x]=b[x]+k;b[y+1]=b[y+1]-k;
#include<iostream> #include<stdio.h> #include<algorithm> #define maxn 500010 typedef long long ll; using namespace std; int n,a[maxn]; ll tree[maxn << 2]; int lowbit(int k) { return k & -k; } void add(int x, ll k) { while (x <= n) { tree[x] += k; x += lowbit(x); } } ll sum(int x) { ll ans = 0; while (x) { ans += tree[x]; x -= lowbit(x); } return ans; } int main() { int m,x, y; ll k; scanf_s("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf_s("%d", &a[i]); add(i,a[i]-a[i-1]); } while (m--) { cin >> k; if (k == 1) { scanf_s("%d%d%lld", &x, &y,&k); add(x, k); add(y + 1, -k); } else { scanf_s("%d", &x); cout << sum(x)<< endl; } } return 0; }
(^o^)/~