• 树状数组


    概念 

    参考博客:http://www.cnblogs.com/George1994/p/7710886.html

    树状数组或者二叉索引树也称作Binary Indexed Tree,又叫做Fenwick树;它的查询和修改的时间复杂度都是log(n),空间复杂度则为O(n),这是因为树状数组通过将线性结构转化成树状结构,从而进行跳跃式扫描。通常使用在高效的计算数列的前缀和,区间和

    lowbit

    它通过公式来得出k,其中k就是该值从末尾开始0的个数。然后将其得出的结果加上x自身就可以得出当前节点的父亲节点的位置或者是x减去其结果就可以得出上一个父亲节点的位置。比如当前是6,二进制就是0110,k为2,那么6+2=8,而C(8)则是C(6)的父亲节点的位置;相反,6-2=4,则是C(6)的上一个父亲节点的位置。

    def LOWBIT(x):
        return x & (-x)

    注意:LOWBIT无法处理0的情况,因为它的结果也是0,那么最终就是一个死循环

    单点修改

    当我们要对最底层的值进行更新时,那么它相应的父亲节点存储的和也需要进行更新,所以修改的代码如下:

    def MODIFY(x, delta):
        if x < 1:
            return
        while x <= n:
            fenwick[x] += delta
            x += LOWBIT(x)

    查询

    而查询的时候,则需要向前进行统计

    def QUERY(x):
        result = 0
        while right > 0:
            result += fenwick[x]
            x -= LOWBIT(x)
        return result

    题目:https://www.nowcoder.com/acm/contest/139/J

    题意:给出n个数,求 [1,L],[R,n]这两个区间不同数的个数
    其实你只要把区间扩大一倍,就是求 [R,L+n]这个区间了

    #include<bits/stdc++.h>
    using namespace std;
    #define MAX 200005
    int bit[MAX],n,q;
    map<int,int>mp;
    struct Query
    {
        int l,r,id;
        bool operator < (const Query& a)const{
          return r<a.r;
        }
    }b[MAX];
    int gsum(int i)
    {
        int s=0;
        while(i>0)
        {
            s+=bit[i];
            i-=i&-i;
        }
        return s;
    }
    void add(int i,int k)
    {
        while(i<=n)
        {
            bit[i]+=k;
            i+=i&-i;
        }
    }
    int main()
    {
        while(~scanf("%d %d",&n,&q)){
          mp.clear();
        memset(bit,0,sizeof(bit));
        vector<int>a(n*2+10),ans(q);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i+n]=a[i];
        }
        n=n*2;
        for(int i=0;i<q;i++)
        {
            int l,r;
            scanf("%d %d",&l,&r);
            b[i].l=r;
            b[i].r=l+n/2;
            b[i].id=i;
        }
        sort(b,b+q);
        int pre=1;
        for(int i=0;i<q;i++)
        {
            for(int j=pre;j<=b[i].r;j++)
            {
                if(mp[a[j]])
                {
                    add(mp[a[j]],-1);
                }
                add(j,1);
                mp[a[j]]=j;
            }
            pre=b[i].r+1;
          ans[b[i].id]=gsum(b[i].r)-gsum(b[i].l-1);
        }
        for(int i=0;i<q;i++)
        {
            printf("%d
    ",ans[i]);
        }
      }
    }

    【进阶——树状数组】 区间求最值

    参考博客:https://www.cnblogs.com/mypride/p/5002556.html

  • 相关阅读:
    [cf1038E][欧拉路]
    [最小费用最大流(板子)]
    [网络流24题]
    [ACM International Collegiate Programming Contest, Amman Collegiate Programming Contest (2018)]
    [Split The Tree][dfs序+树状数组求区间数的种数]
    [CSL 的魔法][求排序最少交换次数]
    [CSL 的字符串][栈,模拟]
    ZOJ 3949 Edge to the Root 树形DP
    第十三周 Leetcode 363. Max Sum of Rectangle No Larger Than K(HARD)
    POJ 2104 HDU 2665 主席树 解决区间第K大
  • 原文地址:https://www.cnblogs.com/linhaitai/p/9553729.html
Copyright © 2020-2023  润新知