木桩涂涂看_树状数组

版权声明:看我干嘛? 你又没打算转载我的博客~ https://blog.csdn.net/wjh2622075127/article/details/81709105

习题:木桩涂涂看

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

输入格式

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

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

输出格式

n 个整数,第 i 个数代表第 i 个木桩总共被涂色的次数。

样例输入

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 ? "":" ");
    }
}

猜你喜欢

转载自blog.csdn.net/wjh2622075127/article/details/81709105