树状数组学习笔记

匿名 (未验证) 提交于 2019-12-02 23:49:02

ǰ׺֪ʶ

lowbit=x&(-x)

lowbit表示的是转换成二进制取第一个一和后面的0得到的数,树状数组经常用到lowbit(原理我也不知道)

树状数组只支持单点修改和前缀查询,其他可以通过拓展

时间复杂度分析:

单点修改O(log n)

前缀和查询O(log n)

树状数组操作:

1.lowbit();

2.modify(x,d);//用于将点x加上数d

3.query(int x);//表示算出到x的前缀和

经典例题

1.洛谷P3374

裸的树状数组,直接按照需要的操作进行单点修改和前缀和查询,在利用前缀和的性质,来算出区间答案

cpp代码如下(代码中,a[i]表示一开始第i项的初始值,s[i]表示编号为i的数在维护的树状数组里,每个编号的数

#include       <map> #include       <set> #include     <ctime> #include     <cmath> #include     <queue> #include     <stack> #include    <cstdio> #include    <vector> #include   <cstring> #include   <cstdlib> #include <iostream> #include<algorithm> #include<cmath> #include<stdlib.h> using namespace std; int a[500005],n,m,s[500005]; int lowbit(int x) {     return x&(-x); } void modify(int x,int d) {     for(int i=x;i<=n;i+=lowbit(i))     {         s[i]+=d;     } } int qusry(int x)//返回前x项的前缀和 {     int sum=0;     for(int i=x;i;i-=lowbit(i))     {         sum+=s[i];     }     return sum; } int main() {     scanf("%d%d",&n,&m);     for(int i=1;i<=n;i++)     {         scanf("%d",&a[i]);         modify(i,a[i]);     }     for(int i=1;i<=m;i++)     {         int xx,x,y,k;         cin>>xx;         if(xx==1)         {             scanf("%d%d",&x,&k);             modify(x,k);         }         if(xx==2)         {             scanf("%d%d",&x,&y);             cout<<qusry(y)-qusry(x-1)<< endl;         }     }     return 0; } 

其实就是由单点修改,变成了区间修改,根据差分数组,只需要由单点修改改成双点修改就可以了

cpp代码如下(带注释)

#include       <map> #include       <set> #include     <ctime> #include     <cmath> #include     <queue> #include     <stack> #include    <cstdio> #include    <vector> #include   <cstring> #include   <cstdlib> #include <iostream> #include<algorithm> #include<cmath> #include<stdlib.h> using namespace std; int n,m,a[500001],s[500001],c[500001];//a数组表示第i项的初始值 int lowbit(int x) {     return x&(-x); } void modify(int x,int d) {     for(int i=x;i<=n;i+=lowbit(i))     {         c[i]+=d;     } } int qusry(int x) {     int sum=0;     for(int i=x;i;i-=lowbit(i))     {         sum=sum+c[i];     }     return sum; } //以上皆为树状数组正常操作 int main() {     scanf("%d%d",&n,&m);     for(int i=1;i<=n;i++)     {         scanf("%d",&a[i]);//读入初始值     }     for(int i=1;i<=n;i++)     {         s[i]=a[i]-a[i-1];//维护一个差分数组         modify(i,s[i]);//将差分数组形成一个新的树状数组     }     for(int i=1;i<=m;i++)     {         int xx,x,y,k;         scanf("%d",&xx);         if(xx==1)         {             scanf("%d%d%d",&x,&y,&k);             modify(x,k);             modify(y+1,-k);             //根据差分数组,只需要将他的头指针+k,(尾指针+1)的指针的值-k,就可以将x~y区间的值都加上k         }         if(xx==2)         {             scanf("%d",&x);             cout<<qusry(x)<< endl;//查询的这个数就为他的差分数组的前缀和         }     }     return 0; } 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!