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\n", 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\n", res);
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,转载请注明出处。

时间: 2024-10-10 16:05:37

poj3468(A Simple Problem with Integers)线段树+树状数组的相关文章

POJ-3468 A Simple Problem with Integers(线段树)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 94899   Accepted: 29568 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj3468 A Simple Problem with Integers 线段树区间更新

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 97722   Accepted: 30543 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj3468 A Simple Problem with Integers(线段树模板 功能:区间增减,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 Description You have N integers, A1, A2, ... , 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 th

POJ3468 A Simple Problem with Integers 【线段树】+【成段更新】

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 57666   Accepted: 17546 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

POJ 3468 A Simple Problem with Integers(线段树区间更新)

题目地址:POJ 3468 打了个篮球回来果然神经有点冲动..无脑的狂交了8次WA..居然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题.区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新.其他的均按线段树的来就行. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <math.h> #include <stac

HDU4267 A Simple Problem with Integers 线段树/树状数组

HDU4267 A Simple Problem with Integers  线段树/树状数组 2012长春网络赛A题 Problem Description Let A1, A2, ... , AN be N elements. You need to deal with two kinds of operations. One type of operation is to add a given number to a few numbers in a given interval. T

POJ3468_A Simple Problem with Integers(线段树/成段更新)

解题报告 题意: 略 思路: 线段树成段更新,区间求和. #include <iostream> #include <cstring> #include <cstdio> #define LL long long #define int_now int l,int r,int root using namespace std; LL sum[500000],lazy[500000]; void push_up(int root,int l,int r) { sum[ro

【POJ】3468 A Simple Problem with Integers ——线段树 成段更新 懒惰标记

A Simple Problem with Integers Time Limit:5000MS   Memory Limit:131072K Case Time Limit:2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each

POJ3468__A Simple Problem with Integers (线段树)

本文出自blog.csdn.net/svitter --我大C++的指针岂是尔等能够简单领悟! 题意 给N个节点,标号A1~An,然后有Q个操作,操作分为Q i j,查询i,j间的区间和.C i j k,i到j个数字,每个数字增加k,并且输出. 输入输出分析 给N,Q,然后跟操作.注意判断Q,C使用scanf("%s"). 测试数据: 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 Samp