Interval maintenance (tree array)

Posted by franknu on Sat, 29 Jan 2022 15:26:36 +0100

Problem Description:

Title Description

Problem solving ideas:

The basic knowledge of tree array will not be repeated here. We only need to know that it can deal with interval maintainability and modifiable RMQ problems, which is more efficient.

The following is the operation of segment tree

  • Single point modification
void update(int x,int k)
{
  for(;x<=n;x=x+(x&(-x))) t[x]+=k;
  //The modification of x position only affects his ancestors, and the ancestors of X happen to increase by X + X & - x, so you can directly modify the value of X's ancestors
  return ;
}
  • Interval query
int sum(int x)
{
   int ans=0;
   for(;x;x-=x&-x) ans+=t[x];
   //Add up all the blocks in the interval to be queried, and the change formula between each block is exactly x-x & - X
   return ans;
}
  • Interval modification and query

If the whole interval modification process is swept away like a single point modification, the tree array will degenerate into a single point Θ ( n l o g n ) \Theta (n log n) Θ (nlogn), so when we face this problem with interval modification, we will try to maintain a differential array d d d.

d i = a i − a i − 1 d_i=a_i-a_{i-1} di​=ai​−ai−1​

It can be found that the difference and prefix sum are inverse operations to each other, if f i f_i fi , represents the differential array d 1 ... d i d1...di d1... The sum of di, then f i = a i f_i=a_i fi = ai, if f i f_i fi , denotes prefix and array s 1 ... s i s1...si s1... si difference, then f i = a i f_i=a_i fi​=ai​ .

According to the characteristics of the original array obtained from the prefix and the difference group, we find that if in the difference array l l l position change a number and change this number + k +k +k. So for the original array l l l all subsequent numbers will be added with k. If we were r r The r position modifies a number so that it subtracts k, then r r The number after r will be subtracted from the original array by k, so these two single point modifications create three intervals:

1 ... l − 1 1...l-1 1... l − 1: unchanged
l ... r l...r l... r: all plus k
r + 1 ... n r+1...n r+1... n: unchanged

Doesn't this realize interval modification? Efficiency is fast!

If we can maintain such a differential array, then the original array a i a_i The prefix and of ai are:

∑ i = 1 n a i = ∑ j = 1 i ∑ k = 1 j d k \sum_{i=1}^{n} a_i=\sum_{j=1}^{i}\sum_{k=1}^{j} d_k i=1∑n​ai​=j=1∑i​k=1∑j​dk​

Not hard to find, d 1 d_1 d1 , will appear in this equation n n n times, d 2 d_2 d2 , will appear n − 1 n-1 n − 1 time, ... ... ... , d i d_i di # will appear n − i + 1 n-i+1 n − i+1 times, so:

∑ i = 1 n a i = ∑ j = 1 i ( d j ∗ n − d j ∗ ( j − 1 ) ) \sum_{i=1}^{n}a_i=\sum_{j=1}^{i} (d_j*n-d_j*(j-1)) i=1∑n​ai​=j=1∑i​(dj​∗n−dj​∗(j−1))

Namely:

∑ i = 1 n a i = n ∗ ∑ j = 1 i d j − ∑ j = 1 i d j ∗ ( j − 1 ) \sum_{i=1}^{n}a_i=n*\sum_{j=1}^{i} d_j-\sum_{j=1}^{i}d_j*(j-1) i=1∑n​ai​=n∗j=1∑i​dj​−j=1∑i​dj​∗(j−1)

Therefore, we only need to maintain two tree arrays separately d i d_i di # and d i ∗ ( i − 1 ) d_i*(i-1) di ∗ (i − 1) can calculate the interval sum according to the above formula.

      if(pos==1)  //Interval modification
      {
        //The operation of interval [c,b] plus d is realized by using differential array
        cin>>d;
        update1(b,d);
        update1(c+1,-d);  //Maintain a tree array of d[i]
        update2(b,d*(b-1));
        update2(c+1,-d*c);  //Maintain a tree array of d[i]*(i-1)
      }
      else
      {
        long long s1,s2;
        s1=(b-1)*sum1(b-1)-sum2(b-1);
        s2=c*sum1(c)-sum2(c);
        //According to the formula, two sections are obtained respectively, and any section is obtained by subtracting the sections
        cout<<s2-s1<<endl;
      }

CODE:

#include <bits/stdc++.h>
using namespace std;
long long n,m,pos,a[100010]={0},b,c,d;
long long t1[100010]={0},t2[100010]={0},o[100010]={0};
inline void update1(int x,int k)
{
  for(;x<=n;x+=x&-x) t1[x]+=k;
  return ;
}
inline void update2(int x,int k)
{
  for(;x<=n;x+=x&-x) t2[x]+=k;
  return ;
}
inline long long sum1(int x)
{
  long long s=0;
  for(;x;x-=x&-x) s+=t1[x];
  return s;
}
inline long long sum2(int x)
{
  long long s=0;
  for(;x;x-=x&-x) s+=t2[x];
  return s;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(register int i=1;i<=n;++i)
    {
      cin>>a[i];
      o[i]=a[i]-a[i-1];
    }
    for(int i=1;i<=n;i++) update1(i,o[i]),update2(i,o[i]*(i-1));
    for(register int i=1;i<=m;++i)
    {
      cin>>pos>>b>>c;
      if(pos==1)
      {
        cin>>d;
        update1(b,d);
        update1(c+1,-d);
        update2(b,d*(b-1));
        update2(c+1,-d*c);
      }
      else
      {
        long long s1,s2;
        s1=(b-1)*sum1(b-1)-sum2(b-1);
        s2=c*sum1(c)-sum2(c);
        cout<<s2-s1<<endl;
      }
    }
    return 0;
}

Topics: C++ SSL Algorithm data structure Binary Indexed Tree