アプリケーションSCAU-1144星の数-HDU-1166-木アレー

この記事の参照
コード提供: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;
}

 

 

例题:

敌兵布阵

 HDU - 1166

 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 }
View Code

 

 

其他的扩展:
区间更新、单点查询(差分建树)
核心:当某个区间[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 }
View Code

区间更新、区间查询:还是利用了差分的思维了
核心:维护两个数状数组,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 }
View Code

 

区间修改、单点查询模板题目:https://www.luogu.org/problem/show?pid=3368

区间修改、区间查询模板题目:https://vjudge.net/problem/POJ-3468
最后再打波广告:https://www.cnblogs.com/xenny/p/9739600.html讲的实在是太好了

おすすめ

転載: www.cnblogs.com/SCAU-gogocj/p/11938997.html