この記事の参照
コード提供:https://www.cnblogs.com/geek1116/p/5566709.html
フェンウィックツリーのコメント:https://www.cnblogs.com/xenny/p/9739600.html
のフェンウィックツリーを知りません学生は友人上記のリンクを見てください、それは素晴らしいことだ(フェンウィックツリーを学んで実際にツリーラインで同じ時間を見に学習することができます)と言う
、このテーマを研究すると見ていることと、また、ツリーラインを行うために使用することができますフェンウィックツリーがhttps://www.cnblogs.com/M-cag/archive/2012/08/16/2642459.html行うために使用することができる
コア、またはこれを行う:2 ^ K = I&( - I)
C [I] = A [I - 2K + 1] + A [I - 2K + 2] + ... + A [i]が
それはA []、他のc-変化をもたらし、Cの[]それに依存するが、A []は含ま変更する場合
A [I]に含まれるC [I + 2K]、C [(I + 2K )+ 2K] ... ;
または塩基性コード(私は下に実施)ビート
ツリーインストールするC []アレイを使用し、元のパッケージに[]配列と以下を、そして
kの^ 2算出する機能をlowbit
lowbit INT(INT X)ここで、// X kがことである
{
( - X)リターン・X;
}
修飾A []あれば、
ボイドの更新(INT I、INT K) //私は、A []変更された位置にKを追加
{
ながら(I <= N-) //あれば、まだ範囲内にすることができるよう私は、変更した
{
C [I] + = Kと、
I + = lowbit(I);
}
}
合計単語
INT GetSum(INT I) // Iに1を見つけ、
{
int型RES = 0;
ながら(I> 0)
{
RES + = C [i]は、
I- = lowbit(I);
}
戻りRES;
}
1144星の数は
問題では、問題の解決策を持っています
制限時間:564MSメモリ制限:65536kも
193渡します:43カウントを提出
質問:プログラミング言語のタイトル:G ++; GCC
説明
天文学者は星を観察するのが好きです。星の各々は、点と、及び星レベル値のその数として左下4.5(より大きくない、すなわち、横軸と縦軸)星のそれぞれれます。
全ては、現在の座標(Nとしてスター数)星を与え、そして星の指定された数の出力レベルを算出しています。
注:同じ座標欠席星
入力フォーマット
最初のラインN
スター座標のN個の動作後は、N(整数座標)に1が
その後Mであり
、Mは、星の数ラインであります
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;
}
例题:
敌兵布阵
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即可了
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);
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讲的实在是太好了