題解/算法 {\2476. 树套树}

題解/算法 {\2476. 树套树}

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

比如[2,3,3,5], 對於操作2, 排名1為2 排名2/3為3 排名4為5; 對於操作1, 2的排名為1 3的排名為2 5的排名為4;

線段樹套Splay; 注意 對於操作3/4/5 都不要調用Update_bySon(會超時), 需要進行優化成log;
操作1: x的排名 定義為<x的個數 + 1, 因此 這符合累加性 (即各個子區間的<x的個數之和 就是整體的答案);
但是對於操作2: 求排名為K的數, 這是無法通過線段樹來求的(即各個子區間的第K小數 並不是整體的第K小數); 正確做法是通過轉換為操作1來二分, 比如[3, 5,5, 7] 求排名為2的數, 那麼反過來: 任意<=3的數 排名是1, [4,5]的排名是2, [6,7]的排名是4, 任意>7的數 排名是5; 我們的答案是5 (即排名為2的是5), 找排名<=K的最大數;

__RetType_Query_ Get_intervalData_rank( int _l, int _r, int _x){ // 操作1
    ASSERT_WEAK_( 0<=_l && _l<=_r && _r<__Range);
    function<__RetType_Query_(__Node_*)> dfs = [&]( __Node_ * _cur){
        _cur->UpdateSon_byLazy();
        if( _l<=_cur->Interval.first && _r>=_cur->Interval.second){ // `cur`不一定是*葉子節點*;
            return _cur->Data.Tr.Get_elementsCount_byLessValue( _x);
        }
        int mid = (_cur->Interval.first+_cur->Interval.second)>>1;
        if( _r <= mid){ return dfs( _cur->SonPtr[0]);} else if( _l > mid){ return dfs( _cur->SonPtr[1]);}
        auto lef = dfs( _cur->SonPtr[0]), rig = dfs( _cur->SonPtr[1]);
        return lef + rig;
    };
    return dfs( __Root) + 1;
}
__RetType_Query_ Get_intervalData_getK( int _l, int _r, int _k){ // 操作2
    ASSERT_WEAK_( 0<=_l && _l<=_r && _r<__Range);
    int l = 0, r = 1e8;
    while( l < r){
        auto mid = (l+r+1)>>1;
        if( Get_intervalData_rank(_l, _r, mid) <= _k){ l = mid;}
        else{ r = mid - 1;}
    }
    return r;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值