(1)用树状数组更新区间,进行单点查询
总体思路:树状数组对应的数组A是一个差分数组,利用树状组数进行单间查询只需要logn的复杂度。
例题:题目链接
Color the ball
N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
Input
每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
当N = 0,输入结束。
Output
每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
Sample Input
3
1 1
2 2
3 3
3
1 1
1 2
1 3
0
Sample Output
1 1 1
3 2 1
#include<iostream> #include<cstring> using namespace std; int n; int a[100005]; int c[100005]; int lowbit(int i){ return i&-i; } void add(int i,int x){ while(i<=n){ c[i]+=x; i+=lowbit(i); } return ; } int sum(int i){ int s=0; while(i>0){ s+=c[i]; i-=lowbit(i); } return s; } int main(){ while(1){ memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); scanf("%d",&n); if(n==0) break; int x,y; for(int i=1;i<=n;i++){ scanf("%d %d",&x,&y); add(x,1); add(y+1,-1); } for(int i=1;i<=n;i++){ int ans=sum(i); if(i==1) printf("%d",ans); else printf(" %d",ans); } printf("\n"); } return 0; }
2、单点更新,区间查询
题目链接
题目大意:
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令
Output
对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。
#include<iostream> #include<cstring> #include<string> using namespace std; int t; int n; int a[50005]; int c[50005]; int lowerbit(int x){ return x&(-x); } void add(int i,int x){ while(i<=n){ c[i]+=x; i+=lowerbit(i); } return ; } int sum(int i){ int sum=0; while(i>0){ sum+=c[i]; i-=lowerbit(i); } return sum; } int main(){ scanf("%d",&t); for(int k=1;k<=t;k++){ cout<<"Case "<<k<<":\n"; memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); add(i,a[i]); } string x; while(1){ cin>>x; if(x=="End") break; int t1,t2; scanf("%d %d",&t1,&t2); if(x=="Query"){ int ans=sum(t2)-sum(t1-1); printf("%d\n",ans); } if(x=="Add"){ add(t1,t2); } if(x=="Sub"){ t2=t2*-1; add(t1,t2); } } } return 0; }
3、树状数组主要是方便,代码简洁,在更新区间,查询区间时已经失去了他的优势,所以我们一般用线段树不用树状数组。