• POJ3468


    POJ3468

    博客图片

    题目链接

    POJ3468

    题目概述

    给出一个包含有(N)个元素的数组(a),然后是(m)次操作,操作有以下两种类型:

    1. Q x y((x leq y))计算(sum_{i = x}^y a[i])
    2. C x y d((x leq y))将区间([x,y])内部的每一个(a[i])加上(d).

    对于第一种查询操作输出对应的结果,数据规模:

    [1leq N,Mleq 10^5, -10^9 leq A_i leq 10^9, -10^4leq dleq 10^4. ]

    题目分析

    经典的树状数组区间修改区间查询的题目,利用初始的前缀和数组和用两个树状数组维持区间修改后的(sum_{i=1}^na[i]).

    利用差分转换的原理可以看看这个差分--OIwiki

    通过:

    [sum_{i=1}^{r+1}(r+1-i+1)cdot f_i - sum_{i=1}^{l}(l-i+1)cdot f_i ]

    代码

    /*
     * @Author: Shuo Yang
     * @Date: 2020-08-04 15:46:50
     * @LastEditors: Shuo Yang
     * @LastEditTime: 2020-08-04 16:58:19
     * @FilePath: /Code/POJ/3468.cpp
     */
    #include<iostream>
    using namespace std;
    typedef long long ll;
    const int N = 1e6+5;
    ll t1[N];
    ll t2[N];
    ll a[N];
    int n;
    
    inline int lowbit(int x){
        return x & -x;
    }
    
    void add(ll*  t, int k, int x){
        while( k <= n){
            t[k] += x;
            k += lowbit(k);
        }
    }
    
    ll sum(ll* t, int k){
        ll ans = 0;
        while( k > 0){
            ans += t[k];
            k -= lowbit(k);
        }
        return ans;
    }
    
    void addL(int lef, int rig, int x){
        add(t1, lef, x);
        add(t2, lef, lef*x);
        add(t1, rig+1, -x);
        add(t2, rig+1, -(rig+1)*x);
    }
    
    int main(int argc, const char** argv) {
        int m;
        scanf("%d %d",&n,&m);
        for(int i = 1; i <=n ; ++i){
            scanf("%lld", &a[i]);
                a[i] += a[i-1];
        }
        for(int i = 0; i <m; ++i){
            char ch;
            int x,y,c;
            while( ch != 'Q' && ch !='C')
                scanf("%c",&ch);
            // printf("ch=%c**
    ", ch);
            if(ch == 'Q'){
                scanf("%d %d", &x,&y);
                ll ans = (a[y]+(sum(t1,y)*(y+1) - sum(t2,y))) - (a[x-1]+(sum(t1,x)*x-sum(t2,x)));
                printf("%lld
    ", ans);
            }else if( ch == 'C'){
                scanf("%d %d %d",&x,&y,&c);
                addL(x,y,c);
            }
        }
        return 0;
    }
    

    这里面的树状数组t1是维护(sum_{i=1}^{n}(n+1)cdot a[i]),t2数组是维护(sum_{i=1}^{n}icdot a[i]).
    区间更新操作是对这两个操作进行的,至于区间求和在原来前缀和的基础上加上这个区间修改后的差分求和得到的就是最终的结果.
    (纯粹的板子,但是我说不清楚,┭┮﹏┭┮2333333).

    其它

  • 相关阅读:
    鼠标划过出现子菜单
    让dedecms(织梦)的list标签支持weight排序
    win7 64位无法安装网络打印机
    点击外部链接, 让iframe父页面也跟着显示
    C/C++指针(转)
    OO与设计模式的原则、目标 (转)
    页面添加QQ
    Windows Form 中的鼠标事件
    深入浅出C#消息
    初始化列表
  • 原文地址:https://www.cnblogs.com/2018slgys/p/13441577.html
Copyright © 2020-2023  润新知