Advanced Data Structures: Tree Arrays and Solving for Inverse Pairs

Tree Array Basics

A tree array is a data structure with log(n) query and modification complexity. Mainly used for single-point modification && interval summation of arrays.

Another one with similar functionality is the line segment tree.

The specific differences and connections are as follows:

  1. The two are at the same level in complexity, but the constants of the tree-like array are obviously better than the line segment tree, and their programming complexity is also much smaller than that of the line segment tree.
  2. The role of the tree-like array is completely covered by the line-segment tree. Any problem that can be solved by using the tree-like array can be solved by using the line-segment tree, but the problem that can be solved by the line-segment tree may not be solved by the tree-like array.
  3. The outstanding feature of tree array is its extreme simplicity of programming. Using lowbit technology, the core operation of tree array can be completed in a few short steps, and its code efficiency is much higher than that of line segment tree.

Lowbit operation explanation

insert image description here

The following is the binary version, you can see that the
update process is to add a binary low 1 each time (101+1 -> 110, 110 + 10 -> 1000, 1000 + 1000 -> 10000)
The query process removes the binary every time The low bit 1 in the middle (1111 - 1 -> 1110, 1110 - 10 -> 1100, 1100 - 100 -> 1000)
explains the specific implementation steps
lowbit(x) is to take out the lowest bit 1 of x; the specific code is:

int lowbit(x){
    
    return x&(-x);}

We know that the negative of a number is equal to the inversion of the number +
1. Take the binary number 11010 as an example: the complement of 11010 is 00101, and the addition of 1 is 00110. The sum of the two is the lowest 1.
Actually, it is very good. Understand that the complement code and the original code must be opposite, so the complement of the original code is all 1. After the complement code is +1, the last 1 and
the rightmost 1 of the original code must be the same position (when the complement is +1). When the first 1 is encountered, the complement of this bit is 0. Since the previous one will be advanced, this bit will become 1)
So we only need to perform a&(-a) to take out the lowest 1
. lowbit, we can perform interval query and single-point update!!!

Single point update

At this point, if we want to change A[1], the following needs to be updated synchronously! ! !
insert image description here

void update(int x,int y,int n){
    
    
    for(int i=x;i<=n;i+=lowbit(i))    //x为更新的位置,y为更新后的数,n为数组最大值
        c[i] += y;
}

Interval query

For example:
i=5
C[4]=A[1]+A[2]+A[3]+A[4];
C[5]=A[5];
can be deduced: sum(i = 5 ) ==> C[4]+C[5];
the serial number is written in binary: sum(101)=C[(100)]+C[(101)];
the first 101, minus the lowest 1 is 100;
In fact, it is the inverse operation of single-point update

int getsum(int x){
    
    
    int ans = 0;
    for(int i=x;i;i-=lowbit(i))
        ans += c[i];
    return ans;
}

Reverse pair for tree array application

principle

Let's think about what problems can be solved by tree arrays. To find the sum of numbers in a certain interval, can we transform the problem of finding inverse pairs in this direction?
We are looking at inverse pairs from another angle: for each number, it may form an inverse pair with the previous number, and it may also form an inverse pair with the latter number. Then let's simplify it. For each number, we only consider it as the inversion pair of the second number in the inversion pair, and then add up such inversion pairs, which is actually the total number of inversion pairs. Why, because each inverse pair has two elements, the first number and the second number. We have considered the case of the second number of the inverse pair, and in fact have considered all the inverse pairs.

topic and code

insert image description here

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+10;
const ll maxm=1e8+10;
ll n;
ll a[maxm],b[maxm];
ll ans=0;
ll lowbit(ll x){
    
    
    return x&(-x);
}
void update(ll x,ll val){
    
    
    for(ll i=x;i<=ans;i+=lowbit(i)){
    
    
        b[i]+=val;
        //cout<<i<<endl;
    }
}
ll getsum(ll x){
    
    
    ll res=0;
    for(ll i=x;i;i-=lowbit(i)){
    
    
        res+=b[i];
    }
    return res;
}
int main(){
    
    
    cin>>n;
    for(int i=1;i<=n;i++){
    
    
        cin>>a[i];
        ans=max(ans,a[i]);
    }
    ll cnt=0;
    for(int i=1;i<=n;i++){
    
    
        update(a[i],1);
        cnt+=i-getsum(a[i]);
        //cout<<i<<endl;
    }
    cout<<cnt;
	return 0;
}

Recommend to everyone


"If you are undecided, you can ask the spring breeze, and if the spring breeze does not speak, you will follow your heart" means: if you are hesitant about something, ask the spring breeze how to do it. . "When you are undecided, you can ask the spring breeze, and if the spring breeze does not speak, you will follow your heart." The sentence comes from the "Sword Comes" by the online writer "Fenghuo Opera Princes". The original text is: "If you are undecided, you can ask the spring breeze. Follow your heart".

insert image description here


Guess you like

Origin blog.csdn.net/weixin_46627433/article/details/123451846