AcWing算法提高课 树状数组

解决的问题:

1、快速求前缀和(logn)(区间求和)

2、修改某一个数(logn)(单点修改)

对比:数组:求前缀和On,修改O1;前缀和数组:求前缀和O1,修改On

 

 

 

 C[x]表示,以x结尾,长度为lowbit(x)的区间中的计数

 

 

 

 

 查询:

修改:

 

 

模板:

复制代码
int a[200010];
LL tr[200010];
int n;

int lowbit(int x)
{
    return x & (-x);
}
int add(int x, int c)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        tr[i] += c;
    }
    return 0;

}
LL sum(int x)
{
    LL res = 0;
    for (int i = x; i > 0; i -= lowbit(i))
        res += tr[i];
    return res;

}
View Code
复制代码

 

 

 对称问题:

区间修改,单点查询

可以转化为对差分数组的单点(两点)修改,区间查询

例题:

AcWing 242. 一个简单的整数问题 

复制代码
#include<bits/stdc++.h>
#include<unordered_set>
using namespace std;
typedef long long LL;

LL a[100010];
LL diff[100010];
LL tr[100010];
int n, m;
LL lowbit(int x)
{
    return x & (-x);
}
void add(LL x, LL c)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        tr[i] += c;
    }
}
LL sum(LL x)
{
    LL res = 0;
    for (int i = x; i > 0; i -= lowbit(i))
    {
        res += tr[i];
    }
    return res;
}
void YD()
{

    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i], diff[i] = a[i] - a[i - 1];
    for (int i = 1; i <= n; i++)
    {
        add(i, diff[i]);
    }
    for (int i = 1; i <= m; i++)
    {
        char op; cin >> op;
        if (op == 'Q')
        {
            int x; cin >> x;
            cout << sum(x) << endl;
        }
        else
        {
            LL l, r, d;
            cin >> l >> r >> d;
            add(r+1, -d);
            add(l, d);
        }
    }

}

int main()
{
    YD();
    return 0;
}
View Code
复制代码

 拓展问题:

区间修改,区间查询

修改依旧使用差分数组。

区间查询,前缀和的前缀和,转化为不同形式的前缀和的差

 

例题:AcWing 243. 一个简单的整数问题2

复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

LL a[100010];
int n, m;
LL tr1[100010];
LL tr2[100010];
LL lowbit(LL x)
{
    return x & (-x);
}
void add(LL x, LL c)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        tr1[i] += c;
    }
}
LL sum(LL x)
{
    LL res = 0;
    for (int i = x; i >0; i -= lowbit(i))
    {
        res += tr1[i];
    }
    return res;
}
void add2(LL x, LL c)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        tr2[i] += c;
    }
}
LL sum2(LL x)
{
    LL res = 0;
    for (int i = x; i > 0; i -= lowbit(i))
    {
        res += tr2[i];
    }
    return res;
}
void YD()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
    {
        add(i, a[i] - a[i - 1]);
        add2(i, (a[i] - a[i - 1])*i);
    }
    while (m--)
    {
        char op; cin >> op;
        if (op == 'C')
        {
            LL l, r, d;
            cin >> l >> r >> d;
            add(l, d);
            add(r + 1, -d);
            add2(l, l*d);
            add2(r + 1, -d*(r+1));
        }
        else
        {
            LL l, r;
            cin >> l >> r ;
            cout << sum(r)*(r + 1) - sum2(r)
                - (sum(l - 1)*(l)-sum2(l - 1))
                << endl;


        }
    }
}

int main()
{
    YD();
return 0;
}
View Code
复制代码

树状数组结合二分例题

244. 谜一样的牛

复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

int a[100010];
int n, m;
int h[100010];
int tr[100010];
int lowbit(int i)
{
    return i & (-i);
}
void add(int x, int c)
{
    for (int i = x; i <= n; i += lowbit(i))
        tr[i] += c;
}
int sum(int x)
{
    int res = 0;
    for (int i = x; i > 0; i -= lowbit(i))
        res += tr[i];
    return res;
}
void YD()
{
    cin >> n;
    a[1] = 0;
    for (int i = 2; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++)
    {
        tr[i] = lowbit(i);
    }
    for (int i = n; i >= 0; i--)
    {
        int index = a[i] + 1;
        int l = 1, r = n;
        while (l < r)
        {
            int mid = (l + r) / 2;
            if (sum(mid) >= index)
                r = mid;
            else
                l = mid + 1;
        }
        h[i] = l;
        add(l, -1);
    }
    for (int i = 1; i <= n; i++) cout << h[i] << endl;
    
}

int main()
{
    YD();
return 0;
}
View Code
复制代码

 

posted @   80k  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示