码迷,mamicode.com
首页 > 编程语言 > 详细

树状数组

时间:2019-08-10 14:15:50      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:printf   lap   print   bsp   color   col   end   isp   hdu   

详细介绍:https://www.cnblogs.com/xenny/p/9739600.html

http://www.sohu.com/a/245746824_100201031

https://www.cnblogs.com/wkfvawl/p/9445376.html

单点更新、单点查询

传统数组可做

1.单点修改+区间查询

int n;//点的数量
int a[50005],c[50005]; //对应原数组和树状数组
int lowbit(int x){
    return x&(-x);
}
void updata(int i,int k){    //在i位置加上k
    while(i <= n){
        c[i] += k;
        i += lowbit(i);
    }
}
//求sum(x)就是a[x]的前缀和,想查询l~r区间的元素和只需要求出来sum(r)-sum(l-1)
int getsum(int i){
    int res = 0;
    while(i > 0){
        res += c[i];
        i -= lowbit(i);
    }
    return res;
}
int main()
{

memset(a,0,sizeof(a));
memset(c,0,sizeof(c));

}

 

模板题:

技术图片
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
//单点修改加区间查询
using namespace std;
int n;
int a[50005],c[50005]; //对应原数组和树状数组
int lowbit(int x){
    return x&(-x);
}
void updata(int i,int k){    //在i位置加上k
    while(i <= n){
        c[i] += k;
        i += lowbit(i);
    }
}
//求sum(x)就是a[x]的前缀和,想查询l~r区间的元素和只需要求出来sum(r)-sum(l-1)
int getsum(int i){
    int res = 0;
    while(i > 0){
        res += c[i];
        i -= lowbit(i);
    }
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        scanf("%d",&n);
        memset(a, 0, sizeof a);
        memset(c, 0, sizeof c);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            updata(i,a[i]);
        }
        printf("Case %d:\n",i);
        char s[10];
        while(cin>>s){
        if(s[0]==Q){//区间查询
        int l,r;
        scanf("%d%d",&l,&r);
        cout<<getsum(r)-getsum(l-1)<<endl;
        }
        if(s[0]==A){//单点增加  第x个数加t
            int x,t;
            scanf("%d%d",&x,&t);
            updata(x,t);
        }
        if(s[0]==S){//单点减少  第x个数减t
            int x,t;
            scanf("%d%d",&x,&t);
            updata(x,-1*t);
        }
        if(s[0]==E)//结束
            break;
        }
    }
}
HDU - 1166

2.区间修改+单点查询

int n,m;
int a[50005] = {0},c[50005]; //对应原数组和树状数组

int lowbit(int x){
    return x&(-x);
}

void updata(int i,int k){    //在i位置加上k
    while(i <= n){
        c[i] += k;
        i += lowbit(i);
    }
}

int getsum(int i){        //求D[1 - i]的和,即A[i]值
    int res = 0;
    while(i > 0){
        res += c[i];
        i -= lowbit(i);
    }
    return res;
}

int main(){
    cin>>n;

     memset(a,0,sizeof(a));
     memset(c,0,sizeof(c));

     for(int i = 1; i <= n; i++){
        cin>>a[i];
        updata(i,a[i] - a[i-1]);   //输入初值的时候,也相当于更新了值
    }
    
    //[x,y]区间内加上k
    updata(x,k);    //A[x] - A[x-1]增加k
    updata(y+1,-k);        //A[y+1] - A[y]减少k
    
    //查询i位置的值
    int sum = getsum(i);

    return 0;
}

例题:P3368 【模板】树状数组 2           https://www.luogu.org/problem/show?pid=3368   

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 //单点修改加区间查询
 7 using namespace std;
 8 int n,m;
 9 int a[500005] = {0},c[500005]; //对应原数组和树状数组
10 
11 int lowbit(int x){
12     return x&(-x);
13 }
14 
15 void updata(int i,int k){    //在i位置加上k
16     while(i <= n){
17         c[i] += k;
18         i += lowbit(i);
19     }
20 }
21 
22 int getsum(int i){        //求D[1 - i]的和,即A[i]值
23     int res = 0;
24     while(i > 0){
25         res += c[i];
26         i -= lowbit(i);
27     }
28     return res;
29 }
30 
31 int main(){
32     int m;
33     cin>>n>>m;
34     memset(a,0,sizeof(a));
35     memset(c,0,sizeof(c));
36     for(int i = 1; i <= n; i++){
37     cin>>a[i];
38     updata(i,a[i] - a[i-1]);   //输入初值的时候,也相当于更新了值
39     }
40     for(int i=1;i<=m;i++)
41     {
42         int t;
43         cin>>t;
44         if(t==1)
45         {
46             int x,y,k;
47             cin>>x>>y>>k;
48              //[x,y]区间内加上k
49            updata(x,k);    //A[x] - A[x-1]增加k
50            updata(y+1,-k);        //A[y+1] - A[y]减少k
51         }
52         else
53         {
54             int kk;
55             cin>>kk;
56             //查询i位置的值
57            int sum = getsum(kk);
58            cout<<sum<<endl;
59         }
60     }
61     return 0;
62 }
View Code

 

3.区间修改+区间查询

int n,m;
int a[50005] = {0};
int sum1[50005];    //(D[1] + D[2] + ... + D[n])
int sum2[50005];    //(1*D[1] + 2*D[2] + ... + n*D[n])

int lowbit(int x){
    return x&(-x);
}

void updata(int i,int k){
    int x = i;    //因为x不变,所以得先保存i值
    while(i <= n){
        sum1[i] += k;
        sum2[i] += k * (x-1);
        i += lowbit(i);
    }
}

int getsum(int i){        //求前缀和
    int res = 0, x = i;
    while(i > 0){
        res += x * sum1[i] - sum2[i];
        i -= lowbit(i);
    }
    return res;
}

int main(){
    cin>>n;
    for(int i = 1; i <= n; i++){
        cin>>a[i];
        updata(i,a[i] - a[i-1]);   //输入初值的时候,也相当于更新了值
    }

    //[x,y]区间内加上k
    updata(x,k);    //A[x] - A[x-1]增加k
    updata(y+1,-k);        //A[y+1] - A[y]减少k

    //求[x,y]区间和
    int sum = getsum(y) - getsum(x-1);

    return 0;
}

例题:https://vjudge.net/problem/POJ-3468

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 //单点修改加区间查询
 7 using namespace std;
 8 #define ll long long
 9 int n,m;
10 ll a[100005] = {0};
11 ll sum1[100005];    //(D[1] + D[2] + ... + D[n])
12 ll sum2[100005];    //(1*D[1] + 2*D[2] + ... + n*D[n])
13 
14 int lowbit(int x){
15     return x&(-x);
16 }
17 
18 void updata(int i,ll k){
19     int x = i;    //因为x不变,所以得先保存i值
20     while(i <= n){
21         sum1[i] += k;
22         sum2[i] += k * (x-1);
23         i += lowbit(i);
24     }
25 }
26 
27 ll getsum(int i){        //求前缀和
28     ll res = 0, x = i;
29     while(i > 0){
30         res += x * sum1[i] - sum2[i];
31         i -= lowbit(i);
32     }
33     return res;
34 }
35 
36 int main(){
37     int Q;
38     ios_base::sync_with_stdio(false);
39 cin.tie(0);
40 cout.tie(0);
41     cin>>n>>Q;
42     for(int i = 1; i <= n; i++){
43         cin>>a[i];
44         updata(i,a[i] - a[i-1]);   //输入初值的时候,也相当于更新了值
45     }
46 
47     for(int i=1;i<=Q;i++)
48     {
49         char c;
50         cin>>c;
51         if(c==Q)
52         {
53             int x,y;
54             cin>>x>>y;
55             long long sum = getsum(y) - getsum(x-1);
56             cout<<sum<<endl;
57         }
58         else
59         {
60             int x,y;
61             ll k;
62             cin>>x>>y>>k;
63              //[x,y]区间内加上k
64             updata(x,k);    //A[x] - A[x-1]增加k
65             updata(y+1,-k);        //A[y+1] - A[y]减少k
66         }
67     }
68     return 0;
69 }
View Code

 

树状数组

标签:printf   lap   print   bsp   color   col   end   isp   hdu   

原文地址:https://www.cnblogs.com/Aiahtwo/p/11331107.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!