码迷,mamicode.com
首页 > 编程语言 > 详细

一天一道算法题——树状数组

时间:2020-03-31 10:29:37      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:style   cout   树状   for   closed   typedef   时间复杂度   play   线段树   

题目【模板】树状数组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;
}
View Code

O(∩_∩)O哈哈~

一天一道算法题——树状数组

标签:style   cout   树状   for   closed   typedef   时间复杂度   play   线段树   

原文地址:https://www.cnblogs.com/zyyz1126/p/12603354.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!