木桩涂涂看_树状数组

习题:木桩涂涂看

n n 个木桩排成一排,从左到右依次编号为 1,2,3...n。每次给定 2 2 个整数 a b b ab),蒜头君便骑上他的电动车从木桩 a a 开始到木桩 b 依次给每个木桩涂一次颜色。但是 n n 次以后 lele 已经忘记了第 i 个木桩已经涂过几次颜色了,你能帮他算出每个木桩被涂过几次颜色吗?

输入格式

第一行是一个整数 n n n100000)。

接下来的 n n 行,每行包括两个整数 a, b (1abn)。

输出格式

n n 个整数,第 i 个数代表第 i i <script type="math/tex" id="MathJax-Element-714">i</script> 个木桩总共被涂色的次数。

样例输入
3
1 1
1 2
1 3
样例输出
3 2 1

看了这位仁兄的博客, 代码非常巧妙精彩, 不过我没看懂.

然后这位仁兄的博客让我知道了为什么, 十分感谢.

这是一个点被多少个区间覆盖的问题, 结果就是求“这个点及它前面的左端点”减去”它前面的右端点”.

这似乎是差分的思想. 树状数组最基本的作用是单点修改区间查询, 而利用差分可以做到区间修改单点查询.

代码1

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

const int maxn = 100005;
int C1[maxn] = {}, C2[maxn] = {};
int n;

void update(int x, int y)
{
    while (x <= n) {
        C1[x]++;
        x += (x & -x);
    }
    while (y <= n) {
        C2[y]++;
        y += (y & -y);
    }
}

int getSum(int x)
{
    int sum1 = 0, sum2 = 0, tmp = x;
    while (tmp >= 1) {
        sum1 += C1[tmp];
        tmp -= (tmp & -tmp);
    }
    tmp = x - 1;
    while (tmp >= 1) {
        sum2 += C2[tmp];
        tmp -= (tmp & -tmp);
    }
    return sum1 - sum2;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int x, y;
        cin >> x >> y;
        update(x, y);
    }
    for (int i = 1; i <= n; ++i) {
        cout << getSum(i) << (i == n ? "":" ");
    }
}

代码2: 树状数组+差分

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int n, C[100005] = {};

void update(int x, int val)
{
    for (; x <= n; x += (x & -x)) {
        C[x] += val;
    }
}

int getSum(int x)
{
    int sum = 0;
    for (; x >= 1; x -= (x & -x)) {
        sum += C[x];
    }
    return sum;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int x, y;
        cin >> x >> y;
        update(x, 1);
        update(y + 1, -1);
    }
    for (int i = 1; i <= n; ++i) {
        cout << getSum(i) << (i == n ? "":" ");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值