• POJ3468 A Simple Problem with Integers(数状数组||区间修改的RMQ问题)


    You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

    Input

    The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
    The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
    Each of the next Q lines represents an operation.
    "C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
    "Q a b" means querying the sum of AaAa+1, ... , Ab.

    Output

    You need to answer all Q commands in order. One answer in a line.

    Sample Input

    10 5
    1 2 3 4 5 6 7 8 9 10
    Q 4 4
    Q 1 10
    Q 2 4
    C 3 6 3
    Q 2 4
    

    Sample Output

    4
    55
    9
    15

    题意:

    • [1,n]区间每个点有初始值,C(x,y,z)操作再[x,y]区间每个点加值z; Q(x,y)询问[x,y]区间的和。

    思路:

    • 显然,线段树+lazy可以很好地解决区间修改问题。

    那么问题来了:

    • 如果非要用树状数组呢?当然可以对修改区间[x,y]的没一个点进行操作,但是一次修改的复杂度就是长度L*lgn,显然是不行的。

    我们从前缀和的思路来解决这个问题,我们以前都用过差分来记录前缀和,然后O(1)地得到区间和:

          例如,[L,R]区间+x ,则sum[L]+=x;  xum[R+1]-=x;最后sum[i]+=sum[i-1];就可以做差得到区间和了。

    但是这里有修改操作,每次询问都sum[i]+=sum[i-1]累加一次肯定是不行的,正确方法如下。

    • STEP1:更新操作:把[l,r]所有的数加上x,可以看做把[l,n]所有数加上x,再把[r+1,n]所有数 减去d。那我们引入一个新的数组delta[n],delta[i]记录了       [i,n]每个数的增量。操作就转化为了 delta[l]+=x,delta[r+1]-=x;
    • STEP2:查询操作:求[l,r]的和,当然是看做求sum[1,r]-sum[1,l-1]啦。就是求sum(x)。 首先,要加上原数组的基数前缀和origin[x],这个一开始就能求出来:   sum[x]=origin[x]=Σa[i];
    • STEP3,考虑delta数组,delta[1]为[1,x]贡献了x个delta[1],delta[2]为[2,x]贡献了x-1个delta[2], 以此类推,delta[i]贡献了(x+1-i)个delta[i]。那么               sum[x]=origin[x]+delta[1]*x+delta[2]*(x-1)+...delta[x] = origin[x]+(x+1)*Σdelta[i]-Σ(i*delta[i]);

    这样就转化为了三个树状数组:orgin可以预处理得到,后面两个可以单点更新得到。

    对比:

    虽然总的来说,线段树能实现的东西比树状数组多。但是能用树状数组解决的方案一般会再空间时间代码量上优于线段树,而且不容易写错,不要问我为什么知道,QwQ。而且二维树状数组也很好写,而线段树。。。。

    线段树代码:

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int maxn=100010;
    int n,m;int a[maxn];
    struct TREE
    {
        ll sum[maxn<<2];int lazy[maxn<<2];
        void build(int Now,int l,int r)
        {
            lazy[Now]=0;
            if(l==r) { sum[Now]=a[l]; return;}
            int Mid=(l+r)>>1;
            build(Now<<1,l,Mid);
            build(Now<<1|1,Mid+1,r);
            pushup(Now);
        }
        void add(int Now,int l,int r,int x,int y,int val)
        {
            if(x<=l&&y>=r) { sum[Now]+=(ll)(r-l+1)*val;lazy[Now]+=val; return ;}
            pushdown(Now,l,r);  int Mid=(l+r)>>1;
            if(y<=Mid) add(Now<<1,l,Mid,x,y,val);
            else if(x>Mid) add(Now<<1|1,Mid+1,r,x,y,val);
            else add(Now<<1,l,Mid,x,Mid,val),add(Now<<1|1,Mid+1,r,Mid+1,y,val);
            pushup(Now);
         }
         ll query(int Now,int l,int r,int x,int y)
         {
            if(x<=l&&y>=r)  return sum[Now];
            pushdown(Now,l,r); int Mid=(l+r)>>1;
            if(y<=Mid) return query(Now<<1,l,Mid,x,y);
            else if(x>Mid) return query(Now<<1|1,Mid+1,r,x,y);
            else return query(Now<<1,l,Mid,x,Mid)+query(Now<<1|1,Mid+1,r,Mid+1,y);
            pushup(Now);
        }
        void pushup(int Now) { sum[Now]=sum[Now<<1]+sum[Now<<1|1];}
        void pushdown(int Now,int l,int r)
        {
            int Mid=(l+r)>>1;
            lazy[Now<<1]+=lazy[Now];sum[Now<<1]+=(ll)(Mid-l+1)*lazy[Now];
            lazy[Now<<1|1]+=lazy[Now];sum[Now<<1|1]+=(ll)(r-Mid)*lazy[Now];
            lazy[Now]=0;
        }
    }Tree;
    int main()
    {
         while(~scanf("%d%d",&n,&m)){
             for(int i=1;i<=n;i++) scanf("%d",&a[i]);
             Tree.build(1,1,n);
             for(int i=1;i<=m;i++){
                    char opt[5];int x,y,z;
                    scanf("%s",opt);
                    if(opt[0]=='Q') scanf("%d%d",&x,&y),printf("%lld
    ",Tree.query(1,1,n,x,y));
                    else scanf("%d%d%d",&x,&y,&z),Tree.add(1,1,n,x,y,z);
             }
         } return 0;
    }
    View Code

    树状数组代码:

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn=100010;
    ll a[maxn],b[maxn],c[maxn];
    char opt[5];int n,m;
    int lowbit(int x) {return x&(-x);}
    void add(int x,int val)
    {
        for(int i=x;i<=n+1;i+=lowbit(i)) 
          b[i]+=val,c[i]+=x*val;
    }
    ll query(int x)
    {
        ll res=a[x];
        for(int i=x;i;i-=lowbit(i)) res+=b[i]*(x+1);
        for(int i=x;i;i-=lowbit(i)) res-=c[i];
        return res;
    }
    int main()
    {
        while(~scanf("%d%d",&n,&m)){
            for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-1];
            for(int i=1;i<=n;i++) b[i]=c[i]=0;
            while(m--){
                scanf("%s",opt); int x,y,z;
                if(opt[0]=='Q')scanf("%d%d",&x,&y),printf("%lld
    ",query(y)-query(x-1));
                else scanf("%d%d%d",&x,&y,&z),add(x,z),add(y+1,-z);
            }
        } return 0;
    }
  • 相关阅读:
    C# 本地文件夹上传至网络服务器中(待续)
    杭州"人才新政22条" 硕士来杭工作一次性补贴2万元
    12.Redis Select 命令
    HTML input 标签不可编辑的 readonly 属性
    让时间处理简单化 【第三方扩展类库org.apache.commons.lang.time】
    java 给指定时间加上天数or给当前日期加天数
    java事务处理
    基于注解的SpringMVC整合JPA
    Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: Cannot open connection
    <%@ include file=""%>与<jsp:include page=""/>两种方式的作用
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8204166.html
Copyright © 2020-2023  润新知