This article reference
code provides: https://www.cnblogs.com/geek1116/p/5566709.html
Fenwick tree Comments: https://www.cnblogs.com/xenny/p/9739600.html
not know Fenwick tree of students do take a look at the link above friends say it's great (in learning Fenwick tree can actually be learning at the same time look at the tree line)
when studying this subject may have a look, it can also be used to do the tree line Fenwick tree can be used to do https://www.cnblogs.com/M-cag/archive/2012/08/16/2642459.html
core or do this: 2 ^ k = i & (- i)
C[i] = A[i - 2k+1] + A[i - 2k+2] + ... + A[i]
If it is to modify a A [] then lead to other c-change, depends on that of c [] contains the A []
A [I] contained in the C [i + 2k], C [(i + 2k ) + 2K] ... ;
or beat the basic code (I practiced under)
below with a [] array to the original package, and then use the C [] array to install tree
^ 2 is calculated function of k lowbit
lowbit int (int X) // X k here is that the
{
return & X (- X);
}
If the modified A [], then
void Update (int i, int k) // add k at position i is changed A []
{
the while (i <= n-) // long as it can still within the scope I have modified the
{
C [I] + = K;
I + = lowbit (I);
}
}
Summing words
int GetSum (int i) // find one to i and
{
int RES = 0;
the while (i> 0)
{
RES + = C [i];
I- = lowbit (i);
}
return RES;
}
1144 the number of stars
the problem has solution to a problem
Time limit: 564MS Memory Limit: 65536K
submit Count: 193 Passes: 43
Questions: Programming language title: G ++; GCC
Description
astronomers like to observe the stars. Each of the stars are regarded as a point, and each of the lower left stars (i.e., the abscissa and ordinate which are not larger than) the stars as its number of stars level value.
All are now given Star (Star number as N) coordinates, and calculates the output level of the specified number of stars.
Note: the same coordinates absent stars
Input format
first line N
after N number behavior of star coordinates 1 to N (an integer coordinates)
Thereafter M is
the line M is the number of stars
N<=100000
M<=1000
坐标范围0<=x,y<=1000000
输出格式
要求依次输出这M个星星的等级,一行一个
输入样例
5
0 0
2 0
3 0
1 1
2 2
2
4 5
输出样例
1
3
思路:一般这种输入x y坐标型的,或者一个物体是有两个属性的话,如果要进行比较的话,一帮都是先对其中一个变量进行排序,然后再吧问题变成了对另外一个变量的比较上了
由于如果要对结构体进行比较的话最好还是用到c++来搞,所以下面代码是用c++来实现的了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <set>
#include <utility>
#define ll long long
#define inf 0x3f3f3f3f
#define MAX_N 100000
#define MAX_X 1000000
using namespace std;
typedef struct node
{
int x,y;
int p; //因为我们对数组进行了重新的排序,但是最好输入的是下标来看他的等级是多少的,所以为了之后可以输入下标得出结果,
//就要再定义一个p来存放原来的下标值的
//所以用个变量p来标记该元素的原下标
} node;
node star[MAX_N+5];//
bool cmp(node a,node b) //按y大小升序来排序,y相同时把x较小的排前面
{
if(a.y!=b.y)
return a.y<b.y;
else
return a.x<b.x;
}
int n,m,maxn;//n表示的是有多少个星星,然后m是要看多少个星星的等级,用maxn来存放星星里面横坐标最大的那个
int ans[MAX_N+5]; //ans[]数组存储每个星星的等级,这个数组的下标表示的是输入数的下标,而并不是x或者y
int bit[MAX_X+5]; //树状数组中的统计和的数组,也就是那个c数组了
int sum(int pos)//就是板子了呢
{
int res=0;
while(pos)
{
res+=bit[pos];//再次说bit[]就是板子里面的c[]
pos-=(pos&-pos);
}
return res;
}
void updata(int pos,int value)//由于是以颗数来搞的,所以value其实就是1了,就是在相应的位置上加1的了
{
while(pos<=maxn)
{
bit[pos]+=value;//把只要和pos位置有关的数组都加1,其实就是输入了这个位置说明就有这个点了,所以和这个点有光的所以的bit[]就加1即可了
pos+=(pos&-pos);
}
}
int main()
{
//freopen("input.txt","r",stdin);
memset(bit,0,sizeof(bit));//这里是没有用到另外一个数组a[]来装原数组的
scanf("%d",&n);
maxn=-1;
for(int i=1; i<=n; i++)
{
scanf("%d%d",&star[i].x,&star[i].y);
star[i].x++; //注意了:在树状下标不能有0,否则会死循环!
star[i].y++; //所以所有的横纵坐标都+1
star[i].p=i;//就是下标,我们是从1开始到n的作为下标的
if(star[i].x>maxn)
maxn=star[i].x; //更新最大的x坐标
}
sort(star+1,star+n+1,cmp);//以y坐标升序来sort
//
for(int i=1; i<=n; i++)
{
ans[star[i].p]=sum(star[i].x); //计算位于其左下方的星星个数,注意这个ans是以这个点的输入的次序也就是下标来的
updata(star[i].x,1); //更新bit[]数组
}
//
scanf("%d",&m);
while(m--)
{
int temp;
scanf("%d",&temp);
printf("%d\n",ans[temp]);
}
return 0;
}
例题:
敌兵布阵
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h>
2 using namespace std;
3
4 int n,m;
5 int a[50005],c[50005]; //对应原数组和树状数组
6
7 int lowbit(int x){
8 return x&(-x);
9 }
10
11 void updata(int i,int k){ //在i位置加上k
12 while(i <= n){
13 c[i] += k;
14 i += lowbit(i);
15 }
16 }
17
18 int getsum(int i){ //求A[1 - i]的和
19 int res = 0;
20 while(i > 0){
21 res += c[i];
22 i -= lowbit(i);
23 }
24 return res;
25 }
26
27 int main(){
28 int t;
29 cin>>t;
30 for(int tot = 1; tot <= t; tot++){
31 cout << "Case " << tot << ":" << endl;
32 memset(a, 0, sizeof a);
33 memset(c, 0, sizeof c);
34 cin>>n;
35 for(int i = 1; i <= n; i++){
36 cin>>a[i];
37 updata(i,a[i]); //输入初值的时候,也相当于更新了值,所有就直接的调用update函数即可了
38 }
39
40 string s;//存放的是指令
41 int x,y;
42 while(cin>>s && s[0] != 'E'){//如果是E的话就结束了
43 cin>>x>>y;//由于只要不是结束的话都是要输入两个数的 x和y的
44 if(s[0] == 'Q'){ //求和操作
45 int sum = getsum(y) - getsum(x-1); //x-y区间和也就等于1-y区间和减去1-(x-1)区间和
46 cout << sum << endl;
47 }
48 else if(s[0] == 'A'){
49 updata(x,y);//在x的位置上加y
50 }
51 else if(s[0] == 'S'){
52 updata(x,-y); //减去操作,即为加上相反数
53 }
54 }
55
56 }
57 return 0;
58 }
其他的扩展:
区间更新、单点查询(差分建树)
核心:当某个区间[x,y]值改变了,区间内的差值是不变的,只有D[x]和D[也就是说问题变成了:原来要更新一个区间的值变成了只需要更新两个点y+1]的值发生改变,
所以我们就可以利用这个性质对D[]数组建立树状数组,
也就是说问题变成了只用在原来的基础上吧第x个的加k,然后第y+1个的减k即可了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int n,m;
2 int a[50005] = {0},c[50005]; //对应原数组和树状数组
3
4 int lowbit(int x){
5 return x&(-x);
6 }
7
8 void updata(int i,int k){ //在i位置加上k
9 while(i <= n){
10 c[i] += k;
11 i += lowbit(i);
12 }
13 }
14
15 int getsum(int i){ //求D[1 - i]的和,即A[i]值
16 int res = 0;
17 while(i > 0){
18 res += c[i];
19 i -= lowbit(i);
20 }
21 return res;
22 }
23
24 int main(){
25 cin>>n;27 for(int i = 1; i <= n; i++){
26 cin>>a[i];
27 updata(i,a[i] - a[i-1]); //输入初值的时候,也相当于更新了值
28 }
29
30 //[x,y]区间内加上k
31 updata(x,k); //A[x] - A[x-1]增加k
32 updata(y+1,-k); //A[y+1] - A[y]减少k
33
34 //查询i位置的值
35 int sum = getsum(i);
36
37 return 0;
38 }
区间更新、区间查询:还是利用了差分的思维了
核心:维护两个数状数组,sum1[i] = D[i],sum2[i] = D[i]*(i-1);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int n,m;
2 int a[50005] = {0};
3 int sum1[50005]; //(D[1] + D[2] + ... + D[n])
4 int sum2[50005]; //(1*D[1] + 2*D[2] + ... + n*D[n])
5
6 int lowbit(int x){
7 return x&(-x);
8 }
9
10 void updata(int i,int k){
11 int x = i; //因为x不变,所以得先保存i值
12 while(i <= n){
13 sum1[i] += k;
14 sum2[i] += k * (x-1);
15 i += lowbit(i);
16 }
17 }
18
19 int getsum(int i){ //求前缀和
20 int res = 0, x = i;
21 while(i > 0){
22 res += x * sum1[i] - sum2[i];
23 i -= lowbit(i);
24 }
25 return res;
26 }
27
28 int main(){
29 cin>>n;
30 for(int i = 1; i <= n; i++){
31 cin>>a[i];
32 updata(i,a[i] - a[i-1]); //输入初值的时候,也相当于更新了值
33 }
34
35 //[x,y]区间内加上k
36 updata(x,k); //A[x] - A[x-1]增加k
37 updata(y+1,-k); //A[y+1] - A[y]减少k
38
39 //求[x,y]区间和
40 int sum = getsum(y) - getsum(x-1);
41
42 return 0;
43 }
区间修改、单点查询模板题目:https://www.luogu.org/problem/show?pid=3368
区间修改、区间查询模板题目:https://vjudge.net/problem/POJ-3468
最后再打波广告:https://www.cnblogs.com/xenny/p/9739600.html讲的实在是太好了