Tree Array Interval Update (using Pseudo Segment Tree) + poj3468 Solution

Posted by Gillesie on Wed, 15 May 2019 11:23:52 +0200

Stuff Don't Say Much First Paste Code Take poj3468 for example

A Simple Problem with Integers
Time Limit: 5000MS      Memory Limit: 131072K
Total Submissions: 123915       Accepted: 38431
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 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 A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+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.
Source

POJ Monthly--2007.11.25, Yang Yi
//Interval Update

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>

using namespace std;
const int N=5e5+10;
long long sum[N];//Prefixes and tree arrays
long long a[N];
long long n,m;
long long ddd[N];//Additive tree array



long long lowbit(long long t)
{
    return t&(-1*t);
}


void update(long long x,long long v, long long t[])
{
//Add v to the start of x and update the k array
    for(int i=x; i<=n; i+=lowbit(i))
    {
        t[i]+=v;
    }
}

long long  getsum(long long x, long long t[])
{
//Find the first prefix and sum of the k-array
    long long  ans=0;
    for(int i=x; i>0; i-=lowbit(i))
        ans+=t[i];
    return ans;
}

void refresh_range(long long i,long long j, long long aa)
{
//Add aa to all the elements in the interval i~j, update the corresponding prefix and tree arrays and add-tree arrays
    update(i,-(i-1)*aa,sum);
    update(i,aa,ddd);
    update(j+1,j*aa,sum);
    update(j+1,-1*aa,ddd);
}

 long long range_sum(long long i,long long j)
{
//Finding the sum of the intervals of i~j
     long long ans=0;
    ans+=getsum(j,sum)+getsum(j,ddd)*j;
    ans-=getsum(i-1,sum)+getsum(i-1,ddd)*(i-1);
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m&&n)
    {
        for(int i=1; i<=n; i++)
        {
            cin>>a[i];
            refresh_range(i,i,a[i]);
        }
 char s;
        for(int i=1;i<=m;i++)
        {


            cin>>s;
            if(s=='C')
            {
                long long x,y,z;
                cin>>x>>y>>z;
                if(x>y)
                    swap(x,y);
                refresh_range(x,y,z);
            }
            else if(s=='Q')
            {
                long long x,y;
                cin>>x>>y;
                if(x>y)
                    swap(x,y);
                cout<<range_sum(x,y)<<endl;
            }
        }
    }
    return 0;
}

We know that when updating a single point, when adding a to the value of a location x, all prefixes and sums of locations before x will not be affected, and all prefixes and sums of locations after X will be affected.

Using single-point update and interval query for interval updating and single-point query, within the range of x < I and x > J (outside the interval to be updated), these prefixes and sums are fixed values as long as the additive a of interval updating is determined, so you do not need to know where to place the single-point query, so this part of work can be done at the time of update, how do you achieve it?

We find that when I <= x <= j, the prefix and increment y = (x-i+1)*a = x*a -(i-1)*a; when x > j, the prefix and increment y = (j-i +1) *a = j*a - (i-1)*a; thus we can conclude that when x >= i, the expression of Y contains - (i-1)*a, so according to the law of prefix sum, we can achieve this by adding this value to the prefix and the prefix at the I position with a single point update.This value is added to all prefixes and sums in the range X >= I.Within the range I <= x <= j, we find that the prefix and incremental expression y except for the part - (i-1)*a, the remaining part is x*a, where x is the location of a single query. This value is uncertain and can only be determined at the time of a single query, so this operation needs to be completed at the time of a single query.In the range of x > j, the prefix and expression y = j*a - (i-1)*a, except for the part of -(i-1)*a that has already been processed at x = i, the remaining part is j*a, which is only related to the endpoint of the interval update and the updated additive a, so it can be processed at the update time, when we need to update the prefix of the j+1 position and the prefix from sum[j+1] to sum[j+1] +J*a.At this point, all values are guaranteed to be correct except for the incorrect values in the query I <= x <= J range.

When the location x of a single-point query is in the range i~j, we need to single-point update the prefix and sum[x] to sum[x] +x*a at the location of X.Now we've finished processing all three intervals, right?But is this really the end?Do you remember the operation of single point update?The operation is as follows: when updating a single point, when adding a to the value of a location x, all prefixes and sums of locations before X are unaffected, and all prefixes and sums of locations after X start are affected.This also means that when the location x of a single-point query is in the i~j range, our single-point update of the X location has actually affected the interval x > J that we already handled when updating the interval, so we need to subtract the value x_a added here because of the single-point update.This also means that we need to store the additive a, otherwise, by the time of single-point query, the additive a will have become the additive after several interval queries.However, the result is correct after the additives of the same interval are overlapped several times.Therefore, we can store the corresponding additions (lazy_tag//equivalent to an ddd array) for each node following the lazy_tag idea of the segment tree.

How can a specific addition be stored and maintained?With the previous analysis ideas, we should be able to store prefix and additive numbers with two tree arrays, one of which is lazy_tag. Assuming that the range of an interval update is i-j and the additive number is a, what we need to do is:

lazy_tag[i] += a; //Add a to all nodes x >= I

lazy_tag[j+1] -= a; //Give x > J all nodes a minus, eliminating the effect of i location processing

This ensures that only additions in the i-j range are added a, which, in conjunction with the interval update operation, ensures that all prefixes and sums are correct.Here, the process of additive numbers is the same as that of the original problem (interval renewal). The problem of adding a to all additives of an interval is essentially the problem of interval renewal.So here, the addition of a position x is not the value of ddd[x], but the prefix and the position X of the DDD tree array.

Topics: iOS