树状数组可以说是一种特殊的线段树,他们有共同的点,BIT通过lowbit来控制线段的长度,可以用于单点修改区间查询,单点查询区间修改,逆序对等等。这里介绍这三种方法来简单描述一下。
一:单点修改区间查询。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e6+10; 4 int n,m; 5 int a[maxn],tr[maxn]; 6 int lowbit(int x){return x& -x;} 7 void add(int point,int dig) {for(int i=point;i<=n;i+=lowbit(i)) tr[i]+=dig;} 8 int ask(int x) 9 { 10 int ans=0; 11 for(int i=x;i>0;i-=lowbit(i)) ans+=tr[i]; 12 return ans; 13 } 14 int main() 15 { 16 memset(tr,0,sizeof(tr)); 17 scanf("%d%d",&n,&m); 18 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 19 for(int i=1;i<=n;i++) add(i,a[i]); 20 while(m--) 21 { 22 int op; scanf("%d",&op); 23 if(op==1){ 24 int x,k; scanf("%d%d",&x,&k); 25 add(x,k); 26 } 27 else{ 28 int x,y; scanf("%d%d",&x,&y); 29 printf("%d\n",ask(y)-ask(x-1)); 30 } 31 } 32 return 0; 33 }
二:单点查询区间修改。(思想在于用前缀和来处理)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn = 5e5+10; 5 int n,m; 6 LL a[maxn],b[maxn],tr[maxn]; 7 LL lowbit(LL x){return x & -x;} 8 void add(int point,LL dig) {for(int i=point;i<=n;i+=lowbit(i)) tr[i]+=dig;} 9 LL ask(int x){ 10 LL ans=0; 11 for(int i=x;i>0;i-=lowbit(i)) ans+=tr[i]; 12 return ans; 13 } 14 int main() 15 { 16 memset(a,0,sizeof(a)); 17 memset(b,0,sizeof(b)); 18 scanf("%d%d",&n,&m); 19 for(int i=1;i<=n;i++){ 20 LL temp; scanf("%lld",&a[i]); 21 b[i]=a[i]-a[i-1]; 22 add(i,b[i]); 23 } 24 while(m--) 25 { 26 int op; scanf("%d",&op); 27 if(op==1) 28 { 29 int x,y; LL k; scanf("%d%d%lld",&x,&y,&k); 30 add(x,k); add(y+1,-k); 31 } 32 else{ 33 int x; scanf("%d",&x); 34 printf("%lld\n",ask(x)); 35 } 36 } 37 return 0; 38 }
三:逆序对。(Focus on this problem's digit!!)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 5e5+10; 4 typedef long long LL; 5 int n,b[maxn];LL tr[maxn]; 6 struct point{ 7 int val,num; 8 }a[maxn]; 9 inline LL read() 10 { 11 int op=1;LL x=0; 12 char ch=getchar(); 13 while(!isdigit(ch)){if(ch=='-') op=-1; ch=getchar();} 14 while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();} 15 return op*x; 16 } 17 bool cmp(point x,point y) 18 { 19 if(x.val==y.val) return x.num<y.num; 20 return x.val<y.val; 21 } 22 LL lowbit(int x){return x&(-x);} 23 void add(int p,int dig){for(;p<=n;p+=lowbit(p)) tr[p]+=dig;} 24 LL ask(int p) 25 { 26 LL res=0; 27 for(;p>0;p-=lowbit(p)) res+=tr[p]; 28 return res; 29 } 30 int main() 31 { 32 memset(tr,0,sizeof(tr)); 33 n=read(); 34 for(int i=1;i<=n;i++){ 35 a[i].val=read(); 36 a[i].num=i; 37 } 38 sort(a+1,a+n+1,cmp); 39 // for(int i=1;i<=n;i++) cout<<a[i].num<<" "<<a[i].val<<'\n'; 40 for(int i=1;i<=n;i++) b[a[i].num]=i; 41 LL ans=0; 42 for(int i=1;i<=n;i++) 43 { 44 add(b[i],1); 45 ans+=i-ask(b[i]); 46 } 47 printf("%lld",ans); 48 return 0; 49 }
BIT的用法当然还有很多,它主要把区间的o(N)降低为o(logN)。