zoukankan      html  css  js  c++  java
  • poj3468(A Simple Problem with Integers)线段树+树状数组

    Description

    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 abc" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
    "Q ab" 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

    Hint

    The sums may exceed the range of 32-bit integers.

    题意:给你n个整数和q个操作,有两种操作,C l r x表示把[l, r]中所有数都加x,Q l r表示输出[l, r]中数值的和。


    用线段树和树状数组都能做。


    方法一:线段树。因为操作一需要修改一个区间内所有的值,所以最坏情况下需要修改整个线段树,复杂度太高。所以可以用线段树来维护两个值,一个是区间共同加上的值,一个是除了这些共同值以外其他的值的和。


    #include <iostream>
    #include <sstream>
    #include <fstream>
    #include <string>
    #include <map>
    #include <vector>
    #include <list>
    #include <set>
    #include <stack>
    #include <queue>
    #include <deque>
    #include <algorithm>
    #include <functional>
    #include <iomanip>
    #include <limits>
    #include <new>
    #include <utility>
    #include <iterator>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    using namespace std;
    typedef long long ll;
    
    const int maxn = (1 << 18) - 1;
    int n, q;
    
    //data维护区间共同值,datb维护除了这些共同值以外的值的和
    ll data[maxn], datb[maxn];
    
    //对区间[a, b)同时加x
    //k是节点的编号,对应的区间是[l, r)
    void add(int a, int b, int x, int k, int l, int r)
    {
        if (a <= l && b >= r)
            data[k] += x;
        else
            if (b > l && a < r)
            {
                datb[k] += (min(b, r) - max(a, l)) * x;
                add(a, b, x, k*2+1, l, (l+r)/2);
                add(a, b, x, k*2+2, (l+r)/2, r);
            }
    }
    
    //计算[a, b)的和
    //k是节点的编号,对应的区间是[l, r)
    ll sum(int a, int b, int k, int l, int r)
    {
        if (b <= l || a >= r)
            return 0;
        if (a <= l && b >= r)
            return (r - l) * data[k] + datb[k];
        ll res = (min(b, r) - max(a, l)) * data[k];
        res += sum(a, b, k*2+1, l, (l+r)/2);
        res += sum(a, b, k*2+2, (l+r)/2, r);
        return res;
    }
    
    int main()
    {
        cin >> n >> q;
        for (int i = 0; i < n; ++i)
        {
            int num;
            scanf("%d", &num);
            add(i, i+1, num, 0, 0, n);
        }
        while (q--)
        {
            char s[5];
            int l, r, x;
            scanf("%s", s);
            if (s[0] == 'C')
            {
                scanf("%d%d%d", &l, &r, &x);
                add(l-1, r, x, 0, 0, n);
            }
            else
            {
                scanf("%d%d", &l, &r);
                printf("%lld
    ", sum(l-1, r, 0, 0, n));
            }
        }
        return 0;
    }
    


    方法二:树状数组。类似地,构建两个树状数组即可。


    #include <iostream>
    #include <sstream>
    #include <fstream>
    #include <string>
    #include <map>
    #include <vector>
    #include <list>
    #include <set>
    #include <stack>
    #include <queue>
    #include <deque>
    #include <algorithm>
    #include <functional>
    #include <iomanip>
    #include <limits>
    #include <new>
    #include <utility>
    #include <iterator>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 100010;
    int n, q;
    
    //BIT
    ll bit0[maxn], bit1[maxn];
    
    ll sum(ll* b, int i)
    {
        ll s = 0;
        while (i > 0)
        {
            s += b[i];
            i &= i - 1;
        }
        return s;
    }
    
    void add(ll* b, int i, int x)
    {
        while (i <= n)
        {
            b[i] += x;
            i += i & (-i);
        }
    }
    
    int main()
    {
        cin >> n >> q;
        for (int i = 1; i <= n; ++i)
        {
            int num;
            scanf("%d", &num);
            add(bit0, i, num);
        }
        while (q--)
        {
            char s[5];
            int l, r, x;
            scanf("%s", s);
            if (s[0] == 'C')
            {
                scanf("%d%d%d", &l, &r, &x);
                add(bit0, l, -x*(l-1));
                add(bit1, l, x);
                add(bit0, r+1, x*r);
                add(bit1, r+1, -x);
            }
            else
            {
                scanf("%d%d", &l, &r);
                ll res = 0;
                res += sum(bit0, r) + sum(bit1, r) * r;
                res -= sum(bit0, l-1) + sum(bit1, l-1) * (l - 1);
                printf("%lld
    ", res);
            }
        }
        return 0;
    }




  • 相关阅读:
    VUE Class动态绑定
    SPA 单页面
    pdf.js使用记录
    vue 采坑 pdfjsdist/es5/build/pdf.js
    搜索引擎搜索技巧
    Service Broker初创建
    SQL Server 2008 R2 SP1升级到SQL Server 2012后的注意事项
    怎么都无法解决的 "Cannot Generate SSPI Context"
    Service Broker 应用示例
    接口测试工具 Jmeter使用笔记(一:编写一个http请求)
  • 原文地址:https://www.cnblogs.com/godweiyang/p/12203961.html
Copyright © 2011-2022 走看看