树状数组的知识总结

Posted thunder-110

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组的知识总结相关的知识,希望对你有一定的参考价值。

 

单点修改:

  不需要差分

 

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

  假设现在有一个原数组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;
}

 

 

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 }
代码

 

以上是关于树状数组的知识总结的主要内容,如果未能解决你的问题,请参考以下文章

牛客竞赛 发电(逆元)(树状数组)

树状数组总结

浅析树状数组

树状数组知识点详解

树状数组总结篇

树状数组的基础知识