zoukankan      html  css  js  c++  java
  • POJ 3468 A Simple Problem with Integers(树状数组区间更新)

    今天来学习一下怎么用BIT区间更新的,BIT速度比线段树速度更快,也更好写。

    我们来看一下当给区间[l,r]整体加上一个常数c会前缀si发生什么变化?

    i < l ,si不变; l ≤ i ≤ r,s增加 了c*(i-l+1); r < i,s增加了c*(r-l+1)。

    如果画出增量与下标的坐标图,我们可以发现两边增加的都是常量,而中间的散点在一条斜率为c的直线上。

    因此我们可以用一个斜率和常数的组合来表示前缀和,si = b1 *i + b2

    那么给区间[l,r]加上c可以表示为:

    1. [l,r]上每个结点的斜率加上c,b1上l位置加c,r+1位置减c。

    2.虽然步骤1更新了[l,r]的斜率,但是增量却往上平移了c*(l-1),因此在b2上l位置减掉c*(l-1)。

    3.最后更新r < i之后的常数,在b2上r+1位置加上掉c*(r)。

    运行效率对比: 未加I/O挂

    BIT 1891ms,线段树(适当维护信息) 2349ms , 线段树(懒操作) 2500ms 。 

    /*********************************************************
    *            ------------------                          *
    *   author AbyssalFish                                   *
    **********************************************************/
    #include<cstdio>
    #include<iostream>
    #include<string>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<stack>
    #include<vector>
    #include<map>
    #include<set>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 1e5+1;
    ll C[2][maxn];
    ll psum[maxn];
    int N;
    inline void add(ll C[],int x,int d)
    {
        while(x <= N){
            C[x] += d;
            x += x&-x;
        }
    }
    
    inline ll sum(ll C[],int x)
    {
        ll ret = 0;
        while(x > 0){
            ret += C[x];
            x &= x-1;
        }
        return ret;
    }
    
    inline ll query(int x){ return sum(C[1],x)*x+sum(C[0],x); }
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif
        int Q; scanf("%d%d",&N,&Q);
        for(int i = 1; i <= N; i++){
            scanf("%I64d", psum + i);
            psum[i] += psum[i-1];
        }
        char op[2];
        while(Q--){
            int l,r; scanf("%s%d%d",op,&l,&r);
            if(*op == 'Q'){
                printf("%I64d
    ",query(r)-query(l-1)+psum[r]-psum[l-1]);
            }else {
                int c; scanf("%d",&c);
                add(C[1],l,c);
                add(C[1],r+1,-c);
                add(C[0],l,c*(1-l));
                add(C[0],r+1,c*(r));
            }
        }
        return 0;
    }
  • 相关阅读:
    Final-阶段站立会议5
    Debug阶段成员贡献分
    每周例行报告——第九周
    beta发布简评
    简易四则运算生成程序——批量出题
    每周例行报告——第八周
    每周例行报告——第七周
    每周例行报告——第六周
    课堂作业:alpha发布点评
    “四则运算生成程序——GUI支持和部分功能改进”链接
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4944959.html
Copyright © 2011-2022 走看看