Solution/algorithm {\255. Kth decimal}

Solution/algorithm {\255. Kth decimal}

@LINK: https://www.acwing.com/problem/content/description/257/;

For array A, find the Kth decimal in the interval A[l...r];
. For example, A = [5,3,2,3,1], for A[123] = [2(1st decimal), 3(1st decimal) 2nd smallest), 3(3rd smallest)];

Algorithm-(persistent segment tree + weighted segment tree)

1: Discretize the array into [0, Range); (of course if min(A)>=0 & amp; & amp; max(A ) is not large There is no need to discretize, that is, Range== max(A));
2: Perform persistent segment tree on the array A[N], that is, there are N versions in total, and the i version of the segment tree is maintainedA[0...i]These numbers; each version of the segment tree is weighted segment tree, that is, the underlying interval of the segment tree is [0 , Range);
For example, A[N] = [4,2,1,2], after discretization is [2,1,0,1] (that is, N= 4, Range=3), for the line segment tree Version[3] (the underlying range is [0, Range)) she maintains 0 ,1,1,2These numbers are the [0].Count=1, [1].Count=2, [2].Count=1 of its leaf nodes, for Version[0] (its underlying range is also [0,Range)) She maintains the number [2] which is the leaf node [2 ].Count=1;

Code
class ___SegmentTree_IntervalOrder{ // For the array `A[]`, query the Kth decimal in the interval `A[l...r]` each time;
//<the specific method is {weight segment tree + persistence}, perform *discretized hashing* on `A[]` and let `N1: set(A[]).size()`, then any version The intervals maintained by the line segment tree are all `[0,N1)`;
// . The `i`th version of the line segment tree maintains the discrete hash values corresponding to the numbers `A[...i]`;
// . The underlying array `[i]` of all versions of the line segment tree corresponds to the same number, that is, the `A[?]`* element whose *discretized hash is equal to `i`;
public:
class __Node_{
public:
    __Node_ *SonPtr[2];
    std::pair<int,int> Interval;

    //{ Data data field
    int Count; //The number of elements in `Interval`; this value must comply with *subtraction*, that is, `[l...r].Count = [0...r].Count - [0... l).Count`;
    //} Data data field

    void Initialize_data(){ // Initialize *all data fields*;
        Count = 0;
    }
    void Update_bySon(){ //Use `SonPtr[0|1].{data field}` to update *all data fields* of the current point;
        Count = SonPtr[0]->Count + SonPtr[1]->Count;
    }
    friend ostream & amp; operator<<( ostream & amp; _cout, const __Node_ & amp; _a){
        return _cout<< ___SupimoTools::Debug::__ToString_items( _a.Interval)<< ", "<< _a.Count;
    }
};

int __Range = 0; // The range of any version of the line segment tree is `[0...Range)`;
vector<__Node_ *> __VersionRoot; // `a: __VersionRoot[b]` represents the `b` version of the line segment tree (that is, maintaining the numbers `A[...b]`);
vector<__Node_> __NodesPool;

__Node_ * __Get_aNewNode(){
    ASSERT_WEAK_( __NodesPool.size() != __NodesPool.capacity());
    __NodesPool.emplace_back(); return &__NodesPool.back();
}
void Initialize( const vector<int> & amp; _arr){
    ASSERT_MSG_( "Ensure that `_arr` is discretized, such as `A=[3,2,3,-1]` then `_arr==[2,1,2,0]`");
    __Range = 1 + *std::max_element( _arr.begin(), _arr.end());
    __NodesPool.reserve( __Range * 4 + std::log2(__Range)*_arr.size()); __NodesPool.clear();
    __VersionRoot.resize( _arr.size());
    { // Initial `0`th version is `arr[0]`:
        static function<__Node_*(int,int)> build = [ & amp;]( int _l, int _r){
            __Node_ * cur = __Get_aNewNode(); cur->Interval = {_l,_r};
            if( _l == _r){ cur->Initialize_data();}
            else{ int mid = (_l + _r)>>1; cur->SonPtr[0] = build( _l, mid); cur->SonPtr[1] = build( mid + 1, _r);}
            return cur;
        };
        __VersionRoot[0] = build(0, __Range-1);

        static function<void(__Node_*)> insert = [ & amp;]( __Node_ * _cur){
            if( _cur->Interval.first == _cur->Interval.second){
                _cur->Count + = 1;
                return;
            }
            int mid = (_cur->Interval.first + _cur->Interval.second)>>1;
            if( _arr[0] <= mid){ insert( _cur->SonPtr[0]);} else{ insert( _cur->SonPtr[1]);}
            _cur->Update_bySon();
        };
        insert(__VersionRoot[0]);
    }
    { // Based on version `0`, create versions `1,2,3,...`
        for( int ver = 1; ver < (int)_arr.size(); + + ver){
            static function<void(__Node_*)> create = [ & amp;]( __Node_ * _cur){
                if( _cur->Interval.first == _cur->Interval.second){
                    _cur->Count + = 1;
                    return;
                }
                int mid = (_cur->Interval.first + _cur->Interval.second)>>1;
                auto neww = __Get_aNewNode();
                if( _arr[ver] <= mid){ *neww = *_cur->SonPtr[0]; _cur->SonPtr[0] = neww; create( _cur->SonPtr[0]);}
                else{ *neww = *_cur->SonPtr[1]; _cur->SonPtr[1] = neww; create( _cur->SonPtr[1]);}
                _cur->Update_bySon();
            };
            __VersionRoot[ver] = __Get_aNewNode(); *__VersionRoot[ver] = *__VersionRoot[ver-1]; create( __VersionRoot[ver]);
        }
    }
}
int Get_intervalData( int _l, int _r, int _Kth){ // Get the Kth decimal in `_arr[l...r]` (for example, `arr[l...r] = {1,2,2, 3}`, then the `K=3` decimal is `3`);
    ASSERT_WEAK_( 0<=_l & amp; & amp; _l<=_r & amp; & amp; _r<(int)__VersionRoot.size());
    ASSERT_WEAK_( 0<=_Kth & amp; & amp; _Kth<(__VersionRoot[_r]->Count - (_l==0?0:__VersionRoot[_l-1]->Count)));
    static function<int(__Node_*,__Node_*)> dfs = [ & amp;]( __Node_ * _rig, __Node_ * _lef)->int{
//><there must be `_lef==nullptr || _rig->Interval==_lef->Interval`;
        ASSERT_( _lef==nullptr || _rig->Interval==_lef->Interval);
        if( _rig->Interval.first == _rig->Interval.second){
            return _rig->Interval.first;
        }
        int count = _rig->SonPtr[0]->Count - (_lef==nullptr?0:_lef->SonPtr[0]->Count);
        if( _Kth < count){ return dfs( _rig->SonPtr[0], (_lef==nullptr?nullptr:_lef->SonPtr[0]));}
        _Kth -= count; return dfs( _rig->SonPtr[1], (_lef==nullptr?nullptr:_lef->SonPtr[1]));
    };
    return dfs( __VersionRoot[_r], (_l==0 ? nullptr:__VersionRoot[_l-1]));
}
void Debug(){
    cout<< "___SegmentTree_IntervalOrder::Debug::Begin\\
";
    for( int version = 0; version < (int)__VersionRoot.size(); + + version){
        vector< pair<int,int> > ANS; // `[(2,1), (3,2)]` This means that the elements maintained by the line segment tree are `{2,3,3}`;
        static function<void(__Node_*)> dfs = [ & amp;]( __Node_ * _cur){
            if( _cur->Count <= 0){ return;}
            if( _cur->Interval.first == _cur->Interval.second){
                ANS.emplace_back( _cur->Interval.first, _cur->Count);
                return;
            }
            else{ dfs( _cur->SonPtr[0]); dfs( _cur->SonPtr[1]);}
            _cur->Update_bySon();
        };
        dfs(__VersionRoot[version]);
        cout<< "Version: "<< version<< ", "<< "Elements: "<< Debug::__ToString( ANS)<< "\\
";
    };
    cout<< "___SegmentTree_IntervalOrder::Debug::End\\
";
}
}; // class ___SegmentTree_IntervalOrder
___SegmentTree_IntervalOrder SegmentTree;

Notes

For example, {1,1,2,2} ranks 1|2nd largest as 1, and ranks 3rd|4th largest as 2 >;

First consider the case of l==1, that is, find the Kth ranking of these numbers A[0...i];
If violence is used, it will explode the space instead of timeout, that is, each A[0...i] will be treated as a separate array; handle explosion SpaceProblems Git Algorithms Can Solve;
For the array A[N], ensure that N is a constant (cannot be changed), discretize it, that is, each A[i] corresponds to An ordinal with >=0 is H(A[i]) (for example, A=[2,2,1 ], then H(1)=0, H(2)=1, let M=maximum ordinal;
The interval of the line segment tree is set to [0, M], and each node [l,r] is set with a Count to represent the individuals in the interval. number (that is, the number of numbers whose ordinal number is [l,r]); for A[0...i], the corresponding line segment tree is for each A[i] are all executed: [H(A[i]), H(A[i])] of the line segment tree Count + = in this interval 1;
. For example, A = [3, 2, 2, 1], M=2; for A[0...2 ] = [3,2,2] Its corresponding line segment tree is: [0(0), 1(2), 2(1)] where a(b ) means that there are b elements of [a] in the line segment tree; because there are 2 2 H(2)=1 code> So there are 2 1’s in the line segment tree; At this time, for example, if you want to find the third largest number, there are 2 numbers in the [0,1] interval, so the answer must be [2,2]Interval, that is, the answer can be found by dividing it into two;
Note that each number’s H() is fixed, so the premise is that your N, that is, the entire array, is fixed and static and cannot be changed;

@DELI;

Code

Note that the count in __Query is the Count in the left child of the current node, not the Count of the current node. >;

void __Insert( int _node_id, int _left, int _right){
//<The current node’s interval is `[left, right]`;
    auto & amp; curNode = Nodes[ _node_id];
    if(_left == _right){
        curNode.Count + + ;
        return;
    }
    auto mid = (_left + _right)>>1;
    int son_id = (__InsertData <= mid ? 0 : 1);
    if(__InsertFlag.first == 1){ // Create a new version based on the parent version
        Nodes.push_back( Nodes[curNode.SonId[son_id]]); curNode.SonId[ son_id] = (int)Nodes.size() - 1;
    }

    if( son_id == 0){ __Insert( Nodes[_node_id].SonId[son_id], _left, mid);}
    else{ __Insert( Nodes[_node_id].SonId[son_id], mid + 1, _right);}

    __Update_fa(Nodes[_node_id], Nodes[Nodes[_node_id].SonId[0]], Nodes[Nodes[_node_id].SonId[1]], _left, _right);
}
void Insert( pair<int,int> _flag, int _data){
//< @IF(`flag.first=1`):[Create a new version with the version number `flag.second` as the parent node (the version number is `VersionRoot.size()`)];
// @ELIF(`flag.first==-1`): [Modify version number `flag.second` directly but make sure *this version must be a leaf node on Git*, that is, there is no `VersionFa[?]=flag. second`];
    ASSERT_( IsInInterval_( _data, 0, __Range-1, true));
    __InsertFlag = _flag; __InsertData = _data;
    int rootId; //The root node of the line segment tree currently being operated;
    if( _flag.first == 1){ // Create a new version based on the parent version
        ASSERT_( IsInInterval_( _flag.second, 0, (int)VersionRoot.size()-1, true));
        rootId = Nodes.size();
        Nodes.push_back( Nodes[ VersionRoot[ _flag.second]]); // Copy
        VersionRoot.push_back( rootId);
        VersionFa.push_back( _flag.second);
    }
    else if( _flag.first == -1){ // Operate on existing version
        ASSERT_( IsInInterval_( _flag.second, 0, (int)VersionRoot.size()-1, true));
        ASSERT_MSG_( "Make sure there is no `VersionFa[?]==flag.second`, that is, this version is a *leaf node* on Git;");
        rootId = VersionRoot[_flag.second];
    }
    else{
        ASSERT_(0);
    }
    __Insert( rootId, 0, __Range-1);
}
int __Query( int _leftNodeId, int _rightNodeId, int _l, int _r){
    if( _l == _r){
        int count = Nodes[_rightNodeId].Count;
        if( _leftNodeId != -1){ count -= Nodes[_leftNodeId].Count;}
        ASSERT_( IsInInterval_( __QueryData, 1, count, true));
        return _l;
    }
    
    int count = Nodes[Nodes[_rightNodeId].SonId[0]].Count;
    if( _leftNodeId != -1){ count -= Nodes[Nodes[_leftNodeId].SonId[0]].Count;}
    //<the definition of `T` is the definition in `@LINK: Query function`. At this time, count represents the *left son information* of the node corresponding to the `[l,r]` interval of the line segment tree `T`;

    int son_id = 0;
    if( __QueryData > count){ son_id = 1; __QueryData -= count;}
    int newLeftId = -1;
    if( _leftNodeId != -1){ newLeftId = Nodes[_leftNodeId].SonId[son_id];}

    int mid = (_l + _r)>>1;
    if( son_id == 0){ return __Query( newLeftId, Nodes[_rightNodeId].SonId[son_id], _l, mid);}
    return __Query( newLeftId, Nodes[_rightNodeId].SonId[son_id], mid + 1, _r);
}
int Query(int _lv, int _rv, int _data){
//< `T` is defined as a line segment tree (this is virtual) constructed with (`[_lv + 1,...,_rv]` newly added numbers in these versions). At this time, it is in `T `Query `data` on this virtual line segment tree;
// . Ensure that `lv` must be the *ancestor node* of `rv` in the Git tree, let the string set corresponding to the TRIE tree of the `lv` version be `SL` and let the string set corresponding to the `rv` version is `SR`, then `T` is equal to the difference set `SR/SL`];
// . Note that `lv,rv` here is very similar to the prefix and idea but there is one difference. It does not contain `lv`, that is, what you are actually querying is `[lv + 1, ..., rv]` This interval (i.e. the modification operations called by these `(lv,rv]` versions);
    ASSERT_( _lv>=-1 & amp; & amp; _lv<=_rv & amp; & amp; _rv>=0 & amp; & amp; _rv<(int)VersionRoot.size());
    __QueryData = _data;
    int rightId = VersionRoot[_rv];
    int leftId;
    if(_lv == -1){
        leftId = -1;
    }
    else{
        ASSERT_MSG_( "Ensure that `lv` must be the *ancestor node* of `rv` in the Git tree");
        leftId = VersionRoot[_lv];
    }
    return __Query( leftId, rightId, 0, __Range-1);
}out;
}
}; // class ___SegmentTree_Persistent



    int N, M; cin>>N>>M;
    vector<int> A(N); for( auto & amp; i : A){ cin>> i;}
    auto B = A; sort( B.begin(), B.end()); B.erase( unique(B.begin(), B.end()), B.end());
    ___SegmentTree_PersistentTr;
    Tr.Initialize( B.size(), 5000006, N + 5);
    FOR_(i, 0, N-1){
        int id = lower_bound( B.begin(), B.end(), A[i]) - B.begin();
        if(i==0){
            Tr.Create();
            Tr.Insert({-1,0}, id);
        }
        else{
            Tr.Insert({1,i-1}, id);
        }
    }
    while( M -- ){
        int l, r, k; cin>>l>>r>>k;
        -- l, -- r;
        cout<< B.at( Tr.Query( l-1, r, k))<< "\\
";
    }