zoukankan      html  css  js  c++  java
  • 树状数组的问题处理

    树状数组能够很容易求出前缀和

    1.对于区间更新问题

    我们要借用辅助函数来帮助自己

    自定义一个函数add[i] , 表示将i~n的数都加了add[i]的值

    那么将[s,t]区间都增加v,就很容易理解为add[s]+=v , add[t+1]-=v了

    查询区间[s,t]的总和的时候就可以理解为:

    ans = sum(t) - sum(s-1) 

    这里只要考虑sum(x)怎么求解即可

    比如原来前i个数保存在a[]中

    那么

    这就很容易理解为是用3个树状数组求一个a[i],一个add[i],一个i*add[i]的前缀和了

    当然这里也可以把a[i]和-add[i]*i合并在一起求前缀和~

     1 #include <cstdio>
     2 #include <cstring>
     3 using namespace std;
     4 #define N 100010
     5 #define lowbit(x) (x&(-x))
     6 #define ll long long
     7 ll sum[N] , add[N] , sub[N];
     8 int n,q;
     9 void initAdd(int p , int v)
    10 {
    11     for(int x=p ; x<=n ; x+=lowbit(x)) sum[x]=sum[x]+v;
    12 }
    13 void update(int s , int t , int v)
    14 {
    15     for(int x=s ; x<=n ; x+=lowbit(x)){
    16         add[x]+=v;
    17         sub[x]+=(ll)s*v;
    18     }
    19     for(int x=t+1 ; x<=n ; x+=lowbit(x)){
    20         add[x]-=v;
    21         sub[x]-=(ll)v*(t+1);
    22     }
    23 }
    24 ll query(int s , int t)
    25 {
    26     ll ans = 0;
    27     for(int x=t ; x>0 ; x-=lowbit(x)) ans+=sum[x]+(ll)(t+1)*add[x]-sub[x];
    28     for(int x=s-1 ; x>0 ; x-=lowbit(x)) ans-=sum[x]+(ll)s*add[x]-sub[x];
    29     return ans;
    30 }
    31 int main()
    32 {
    33   //  freopen("a.in" , "r" , stdin);
    34     while(~scanf("%d%d" , &n , &q)){
    35         memset(sum,0,sizeof(ll)*(n+1));
    36         memset(add,0,sizeof(ll)*(n+1));
    37         memset(sub,0,sizeof(ll)*(n+1));
    38         int x;
    39         for(int i=1; i<=n ; i++){
    40             scanf("%d" , &x);
    41             initAdd(i,x);
    42         }
    43         char op[2];
    44         while(q--){
    45             scanf("%s" , op);
    46             int a,b,c;
    47             if(op[0]=='Q'){
    48                 scanf("%d%d" , &a , &b);
    49                 printf("%I64d
    " , query(a,b));
    50             }else{
    51                 scanf("%d%d%d" , &a , &b , &c);
    52                 update(a , b , c);
    53             }
    54         }
    55     }
    56     return 0;
    57 }
    POJ3648

     2.树状数组求解区间极值问题

    静态求区间极大极小可以用MST或者线段树做,同样也可以用树状数组像MST一样写出精简的代码

    另外他比MST更强的是,他同样可以处理在单点更新下的问题

    对于一个数组a[],如何初始化对应的树状数组:

    对于每一个树状数组上的点,我们要思考它往下走到的是树上的哪些点,对于每一个树状数组上的点i来说

    它所有的儿子其实是lowbit(i)的位数-1

    所以这么表示for(int x=1 ; x<lowbit(i) ; x<<=1) //operation;

    但这里注意的是这里  i-x 才是它的儿子节点

    所以初始化就是

    void init()
    {
        for(int i=1; i<=n ; i++){
            Max[i]=a[i];
            for(int x=1 ; x<lowbit(i) ; x<<=1) Max[i]=max(Max[i],Max[i-x]);
        }
    }

    简单的点更新只要去不断往上更新树上的父亲节点直到结束即可

    void update(int p , int v)
    {
        a[p] = v;
        for(int x=p ; x<=n ; x+=lowbit(x)) Max[x] = max(Max[x] , v);
    }

    区间最大值的询问可以很容易的思考,如果从当前位置pos出发,可以走最长的lowbit(pos)就是这个pos点可覆盖的长度后还在区间范围内就说明是可行的,我们当然要走最大的,否则就只移动一格就可以了- -,这个移动一格的次数不会多的,所以不要误认为这里会超时

    int query(int s , int t)
    {
        int ans = a[t];
        for(int x=t-1 ; x>=s ; ){
            if(x-lowbit(x)>=s-1) ans = max(ans , Max[x]) , x-=lowbit(x);
            else ans = max(ans , a[x]) , x--;
        }
        return ans;
    }
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 #define N 200000
     6 #define lowbit(x) (x&(-x))
     7 #define max(a,b) a>b?a:b
     8 int a[N+2] , Max[N+2] , n , m;
     9 void init()
    10 {
    11     for(int i=1; i<=n ; i++){
    12         Max[i]=a[i];
    13         for(int x=1 ; x<lowbit(i) ; x<<=1) Max[i]=max(Max[i],Max[i-x]);
    14     }
    15 }
    16 void update(int p , int v)
    17 {
    18     a[p] = v;
    19     for(int x=p ; x<=n ; x+=lowbit(x)) Max[x] = max(Max[x] , v);
    20 }
    21 int query(int s , int t)
    22 {
    23     int ans = a[t];
    24     for(int x=t-1 ; x>=s ; ){
    25         if(x-lowbit(x)>=s-1) ans = max(ans , Max[x]) , x-=lowbit(x);
    26         else ans = max(ans , a[x]) , x--;
    27     }
    28     return ans;
    29 }
    30 int main()
    31 {
    32    // freopen("a.in" , "r" , stdin);
    33     while(~scanf("%d%d" , &n , &m)){
    34         for(int i=1 ;i<=n ; i++) scanf("%d" , &a[i]);
    35         init();
    36         char op[2]; int s,t;
    37         while(m--){
    38             scanf("%s%d%d", op , &s , &t);
    39             if(op[0]=='Q') printf("%d
    " , query(s,t));
    40             else update(s,t);
    41         }
    42     }
    43     return 0;
    44 }
    HDU1754 I hate it
  • 相关阅读:
    在Objective-C声明Block的几种方式
    属性初始化
    OC协议
    堆排序的OC实现
    iOS 应用性能测试的相关方法、工具及技巧
    墙裂推荐 iOS 资源大全
    剖析@weakify 和 @strongify
    iOS开发大神必备的Xcode插件
    聊聊 KVC 和 KVO 的高阶应用
    TableView的优化
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/5337938.html
Copyright © 2011-2022 走看看