• 树状数组—区间修改+单点查询 详解


    看了很长时间大佬的博客,终于明白了区间修改和单点查询的原理,因为大佬们的思维比较强大,所以菜鸡决定写一篇较为详细的解释。

     

    首先引入差分数组d,设原数组为a,令d[i]=a[i]-a[i-1].由此关系式得,也就是a[j]等于d[j]的前 j 项和,即前缀和。

    于此,我们的树状数组维护的是 d 的前缀和

    1、单点查询

    有以上推理得,查询a[i]相当于查询b[i]的前缀和,用树状数组操作即可。(注意:树状数组维护的是d数组,不是原数组!)

    2、区间修改:

    因为对a的区间[i,j]加x,就相当于a[i]比a[i-1]大x,a[j+1]比a[j]小x,就相当于对a[i]加x,对a[j+1]减x。

    因为a[i]等于d[i]的前缀和,所以a[i]+x就相当于对d[i]的前缀和加x,可以用树状数组操作。

    同理,a[j+1]-x等于b[j+1]的前缀和减x,用树状数组操作。

    上一道经典例题:Color the ball   HDU - 1556  

    N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?

    Input

    每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。 
    当N = 0,输入结束。

    Output

    每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。

    Sample Input

    3
    1 1
    2 2
    3 3
    3
    1 1
    1 2
    1 3
    0

    Sample Output

    1 1 1
    3 2 1
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<iostream>
    using namespace std;
    typedef long long  LL;
    const double pi=acos(-1.0);
    const double e=exp(1);
    const int N = 100010;
    
    #define lson i << 1,l,m
    #define rson i << 1 | 1,m + 1,r
    
    int c[N];
    int sum[N];
    int ans[N];
    
    int lowbit(int x)
    {
        return x=x&(-x);
    }
    
    void update(int i,int v)
    {
        while(i<=N)
        {
            c[i]+=v;
            i+=lowbit(i);
        }
    }
    
    int getsum(int i)
    {
        int x=0;
        while(i>0)
        {
            x+=c[i];
            i-=lowbit(i);
        }
        return x;
    }
    
    int main()
    {
        int i,p,j,n;
        int a,b;
        while(1)
        {
            scanf("%d",&n);
            if(n==0)
                break;
            memset(sum,0,sizeof(sum));
            memset(c,0,sizeof(c));
            for(i=1;i<=n;i++)
            {
                scanf("%d%d",&a,&b);
                update(a,1);
                update(b+1,-1);
            }
            for(i=1;i<=n;i++)
            {
                if(i!=n)
                    printf("%d ",getsum(i));
                else
                    printf("%d
    ",getsum(i));
            }
        }
        return 0;
    }
  • 相关阅读:
    双11专刊|云原生数据仓库AnalyticDB支撑双11,大幅提升分析实时性和用户体验
    LeetCode_Binary Tree Inorder Traversal
    LeetCode_4Sum
    LeetCode_Add Binary
    LeetCode_Add Two Numbers
    LeetCode_3Sum Closest
    Building CEGUI with Ogre 1.8.1
    LeetCode_3Sum
    LeetCode_Climbing Stairs
    LeetCode_Binary Tree Level Order Traversal
  • 原文地址:https://www.cnblogs.com/daybreaking/p/9408301.html
Copyright © 2020-2023  润新知