/*
1. sum[i] 从num[1]+...+num[i]的和 O(1)
2. 线段数 O(logn)
3. 树状数组 O(logn)
区别:
1.线段数和树状数组可以修改,而前缀和不能修改。
2.树状数组空间复杂度较低。
*/
#include<cstdio>
#include<cstring>
#define lowerBit(x) (x&(-x))
int num[10000];
int n;
/*
第一种: x&(-x)
int x=0000000000000001010100
-x -> 1000000000000001010100 -> 111111...11110101011 -> 11111111110101100
0000000000000001010100
1111111111111110101100
&
-----------------------
0000000000000000000100
第二种:x-(x&(x-1))
int x=0000000000000001010100
0000000000000001010100
0000000000000001010011
&
-----------------------
0000000000000001010000
0000000000000001010100
0000000000000001010000
-
-----------------------
0000000000000000000100
*/
//一个数所管辖的数都小于这个数的下标,这个数二进制末尾的1的位置i,2^i就是这个数管的数的个数
void UpDate(int x,int y) //把第x个数加y
{
while (x <= n)
{
num[x] += y;
x = x+lowerBit(x);//x加上最末尾出现的1和1后面的零表示的十进制的值
}
}
int Query(int x) //求从1到x的和
{
int sum = 0;
while (x > 0)
{
sum += num[x];
x = x-lowerBit(x);//x&(x-1)//x减去最末尾出现的1和1后面的零表示的十进制的值
}
return sum;
}
int main()
{
scanf ("%d",&n);
memset(num,0,sizeof(num));
for (int i = 1 ; i <= n ; i++)
{
int t;
scanf ("%d",&t);
UpDate(i,t);
}
int m;
scanf ("%d",&m);
while (m--)
{
int x,y;
scanf ("%d %d",&x,&y);
printf ("%d\n",Query(y)-Query(x-1));
}
return 0;
}
【树状数组模板】
最新推荐文章于 2025-05-25 19:04:27 发布