zoukankan      html  css  js  c++  java
  • 树状数组的知识总结

    单点修改:

      不需要差分

    区间修改,单点查询: //参考

      假设现在有一个原数组a(假设a[0] = 0),有一个数组d,d[i] = a[i] - a[i-1],那么

    a[i] = d[1] + d[2] + .... + d[i]

    d数组就是差分数组

    所以求a[i]就可以用树状数组维护d[i]的前缀和

    区间修改,单点查询:

    根据d的定义,对[l,r]区间加上x,那么a[l]和a[l-1]的差增加了x,a[r+1]与a[r]的差减少了x,所以就对差分数组的前缀和进行修改

    设c是差分数组的前缀和

    注意:差分 输入的时候要以差的形式

    for(int i=1;i<=n;i++)
    {
        scanf("%d",&y);
        add(i,y-x);
        x=y;
    }
    void add(int x,int k)
    {
        for (int i = 1;i <= n;i += lowbit(i)) c[i] += k;
    }
    {
        add(l,x);  //差分
        add(r+1,-x);
    }
    int sum(int x)
    {
        int ans = 0;
        for (int i = x;i > 0;i -= lowbit(i)) ans += c[i];
        return ans;
    }

    区间修改,区间查询:

      根据上面的差分数组的定义可以得到:

    a[1] + a[2] + a[3] + ... + a[k] = d[1] + d[1] + d[2] + d[1] + d[2] + d[3] + ... + d[1] + d[2] + d[3] + ... + d[k]

                  = Σ(k - i + 1) * d[i]  (i从1到k)

    变化一下 Σa[i] (i从1到k) = Σ(k+1) * d[i] - i * d[i] (i从1到k)

    d[i]可以用一个前缀和维护,i * d[i]也可以用一个前缀和进行维护,所以区间修改,区间查询就变得很方便了

    假设c1维护d[i]的前缀和,c2维护d[i] * i的前缀和

    void add(int x,int y)
    {
        for (int i = x;i <= n;i += lowbit(i)) c1[i] += y,c2[i] += x * y;
    }
    {
        add(l,x);
        add(r+1,-x);
    }
    int sum(int x)
    {
        int ans1 = 0;
        int ans2 = 0;
        for (int i = x;i > 0;i -= lowbit(i))
        {
            ans1 += (x + 1) * c1[i];
            ans2 += c2[i];
        }
        return ans1 - ans2;
    }

    树状数组求 逆序对:

    方法1的博客 (但有0就死循环了,所以前提a[i]>0)

      但又局限性,a[ i ]的最大值不能很大,否则数组会爆

     因此,引进离散化+树状数组

    方法2的博客

      a[i].num  3 7 2 4 6

      a[i].pos   1 2 3 4 5

     对结构体a按num值从小到大排序,得到:

      a[i].num  2 3 4 6 7

      a[i].pos   3 1 4 5 2

     for(int i=1;i<=n;i++)  aa[ a[i].pos ]=i;   会得到:

      i:     1 2 3 4 5

      aa[i]:    2 5 1 3 4

    这样的 aa[i]中各位数字 2 5 1 3 4的相对大小和原数组a[i].num  3 7 2 4 5 是一样的。这样做减少了不必要的空间。 a[i] 可为0

    去重离散化的两种方法:

    struct node
    {
        int v,p;
    }aa[N];
    
    bool cmp(node x,node y)
    {
        return x.v<y.v;
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++) scanf("%d",&aa[i].v),aa[i].p=i;
        sort(aa+1,aa+1+n,cmp);
        int cnt=0;
        for(int i=1; i<=n; i++) {
            if(aa[i].v != aa[i-1].v) {
                cnt++;
            }
            a[aa[i].p] = cnt;
        }
    }
    去重离散化1
    for(i=1;i<=n;++i) cin>>a[i], b[i]=a[i];
    
    void discretize(){
        sort(b+1,b+1+n);
        unique(b+1,b+1+n)-b-1;
        for(i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+n,a[i])-b;
    }
    去重离散化2
    vector<int> v;
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end())  , v.end());
    ...=lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
    去重离散化3

    第二种去重不太彻底,5 8 8 10,离散化之后是 1 2 2 4

    hdu二维树状数组题:新年彩灯2

     思路:二维转为多个一维的就行了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include <cctype>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cmath>
     7 #include<string>
     8 #include<cmath>
     9 #include<set>
    10 #include<vector>
    11 #include<stack>
    12 #include<queue>
    13 #include<map>
    14 using namespace std;
    15 #define ll long long
    16 #define mem(a,x) memset(a,x,sizeof(a))
    17 #define se second
    18 #define fi first
    19 const ll mod=1e9+7;
    20 const int INF= 0x3f3f3f3f;
    21 const int N=1e6+5;
    22 
    23 int c[1005][1005];
    24 int n,m;
    25 
    26 int lowbit(int i)
    27 {
    28     return i&-i;
    29 }
    30 
    31 void add(int x,int y,int k)
    32 {
    33     for(int i=y;i<=n;i+=lowbit(i)) c[x][i]+=k;
    34 }
    35 
    36 int sum(int x,int y)
    37 {
    38     int sum=0;
    39     for(int i=y;i>0;i-=lowbit(i)) sum+=c[x][i];
    40     return sum;
    41 }
    42 
    43 int main()
    44 {
    45     int x,y,k,q,a1,a2,b1,b2;
    46     //int cnt=0;
    47     //printf("Case %d:
    ",++cnt);    
    48     while(m--)
    49     {
    50         cin>>q;
    51         if(q==1)
    52         {
    53             scanf("%d%d%d%d",&a1,&b1,&a2,&b2);
    54             if(a1>a2) a1=a1^a2,a2=a1^a2,a1=a1^a2;
    55             if(b1>b2) b1=b1^b2,b2=b1^b2,b1=b1^b2;
    56 
    57             for(int i=a1;i<=a2;i++)
    58             {
    59                 add(i,b1,1);
    60                 add(i,b2+1,-1);
    61             }
    62         }
    63         else
    64         {
    65             scanf("%d%d",&x,&y);
    66             if(sum(x,y)%2==0) cout<<0;
    67             else cout<<1;
    68             
    69             cout<<endl;
    70         }
    71     }
    72 }
    代码
  • 相关阅读:
    Truck History(poj 1789)
    Highways poj 2485
    117. Populating Next Right Pointers in Each Node II
    116. Populating Next Right Pointers in Each Node
    115. Distinct Subsequences
    114. Flatten Binary Tree to Linked List
    113. Path Sum II
    109. Convert Sorted List to Binary Search Tree
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
  • 原文地址:https://www.cnblogs.com/thunder-110/p/10294042.html
Copyright © 2011-2022 走看看