• 树状数组


    概念 

    参考博客: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

  • 相关阅读:
    My Vim
    POJ 3292 Semi-prime H-numbers
    洛谷P3954 成绩【民间数据】
    数据结构—栈/队列
    说服式设计(persuasive design)的行为模型
    发送邮件给某人:mailto标签
    如何识别和利用用户情绪
    HDU Good Numbers (热身赛2)
    atlas z 轴
    什么叫“默认邮件客户端没有正确安装”?
  • 原文地址:https://www.cnblogs.com/linhaitai/p/9553729.html
Copyright © 2020-2023  润新知