ErikTse Runtime

  • 首页 / Home
  • | 算法学习 / Algorithm
    • 所有 / All
    • 简单 / Easy
    • 中等 / Medium
    • 困难 / Hard
  • | 技术分享 / Technology
    • 所有 / All
    • 网络技术 / NetWork
    • 资源共享 / Resource
    • 项目实践 / Event
Keep Going.
温故而知新.
  1. 首页
  2. 算法学习
  3. 简单
  4. 正文

树状数组维护区间和讲解

2023年3月19日 40点热度 2人点赞 0条评论

树状数组

树状结构,用数组来模拟,开O(n)的空间即可。

一般是权值树,原数组的“值”作为树状数组的“下标”。

动态维护区间和

a = [1, 2, 3, 4, 5]

t = [....]

lowbit:lowbit(x) = x & -x;

t[i]的管辖区间:[i - lowbit(i) + 1, i]

单点修改 向右走

复杂度O(logn)

add(int k, int x);

1.找到点k所在的所有区间,+lowbit找到父亲(父亲的管辖区间一定比自己的大,且包含自身)

2.给所有途经的区间加上x

3.修改的值,和途经节点无关,只和初始节点有关

区间查询 向左走

复杂度O(logn)

int getsum(int k);

1.找到点k所在的最右边的区间,t[k],然后往左走,直到走不动了

2.把沿途的节点的值全部加起来

区间修改

前面全部都是修改,后面全部都是查询的话:前缀和+差分

维护的就是两个差分数组diff。

d1[]维护di,d2维护di * (i - 1)。

修改的值,和途经节点无关,只和初始节点有关。

例题

https://ac.nowcoder.com/acm/problem/15163

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 1e5 + 9;

int a[maxn], t[maxn], n;

int lowbit(int x){return x & -x;}

void add(int k, int x)//给点k加上值x
{
    //点k所在的第一个区间是k(最下面这个区间)
    for(int i = k;i <= n; i += lowbit(i))t[i] += x;
}

int getsum(int k)//返回原数组a中区间[1, k]的和
{
    int res = 0;
    for(int i = k;i > 0; i -= lowbit(i))res += t[i];
    return res;
}


signed main()
{
    scanf("%lld", &n);

    for(int i = 1;i <= n; ++ i)scanf("%lld", a + i);

    int ans = 0;
    for(int i = 1;i <= n; ++ i)
    {
        //把值在[a[i] + 1, ...)的所有个数加起来

        ans += i - 1 - getsum(a[i]);
        add(a[i], 1);
    }

    printf("%lld\n", ans);
    return 0;
}

https://ac.nowcoder.com/acm/problem/15175

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 1e5 + 9;

int a[maxn], d[maxn], di_1[maxn], n, m;

int lowbit(int x){return x & -x;}

void add(int k, int x)//给点k加上值x
{

    //d[] += x, di_1[] += x * (k - 1)
    //点k所在的第一个区间是k(最下面这个区间)
    for(int i = k;i <= n; i += lowbit(i))d[i] += x, di_1[i] += x * (k - 1);
}

int getsum(int k)//返回原数组a中区间[1, k]的和
{
    int res = 0;
    for(int i = k;i > 0; i -= lowbit(i))res += k * d[i] - di_1[i];
    return res;
}


signed main()
{
    scanf("%lld %lld", &n, &m);

    for(int i = 1;i <= n; ++ i)scanf("%lld", a + i);

    for(int i = 1;i <= n; ++ i)add(i, a[i]), add(i + 1, -a[i]);

    while(m --)
    {
        char s[5];scanf("%s", s);
        char op = s[0];

        if(op == 'Q')
        {
            int l, r;scanf("%lld %lld", &l, &r);
            printf("%lld\n", getsum(r) - getsum(l - 1));
        }
        else if(op == 'C')
        {
            int l, r, v;scanf("%lld %lld %lld", &l, &r, &v);
            add(l, v), add(r + 1, -v);
        }
    }

    return 0;
}

天梯赛L3-1

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6 + 9;
int n, m, t[maxn];

struct Q
{
    int l, r, v;
    bool operator < (const Q &b)const
    {
        return r < b.r;
    }
}q[maxn];//m个查询

int lowbit(int x){return x & -x;}

void add(int k, int x)//在点k上增加x
{
    for(int i = k;i <= n;i += lowbit(i))t[i] += x;
}

int getsum(int k)//返回[1, k]的和
{
    int res = 0;

    for(int i = k;i ; i -= lowbit(i))res += t[i];

    return res;
}

signed main()
{
    scanf("%lld %lld", &n, &m);

    for(int i = 1;i <= m; ++ i)
        scanf("%lld %lld %lld", &q[i].l, &q[i].r, &q[i].v);

    sort(q + 1,q + 1 + m);//r升序

    for(int i = 1;i <= m; ++ i)
    {
        int l = q[i].l, r = q[i].r, v = q[i].v;

        int sum = getsum(r) - getsum(l - 1);
        if(sum < v)add(r, v - sum);
    }

    for(int i = 1;i <= n; ++ i)
        printf("%lld ", getsum(i) - getsum(i - 1));

    return 0;
}
本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: C++ 区间和 树状数组 算法竞赛
最后更新:2023年3月19日

Eriktse

19岁,性别未知,ACM-ICPC现役选手,ICPC亚洲区域赛银牌选手,CCPC某省赛铜牌蒟蒻,武汉某院校计算机科学与技术专业本科在读。

点赞
< 上一篇

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

订阅本站
Loading
文章目录
  • 树状数组
    • 动态维护区间和
      • 单点修改 向右走
      • 区间查询 向左走
      • 区间修改
    • 例题
      • https://ac.nowcoder.com/acm/problem/15163
      • https://ac.nowcoder.com/acm/problem/15175
      • 天梯赛L3-1

COPYRIGHT © 2022 ErikTse Runtime. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

赣ICP备2022001555号-1

赣公网安备 36092402000057号