Loading

mark:pb_ds 普通平衡树

#include <bits/extc++.h>
#include <cstdio>
#define inf 998244353
using namespace __gnu_pbds;
using pai = std::pair<int, int> ;
tree <pai, null_type, std::less<pai>, rb_tree_tag, tree_order_statistics_node_update> tr;
int read(){
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x * f;
}
void write(int x){
    if(x < 0) {putchar('-'); x = -x;}
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
    return;
}
int n, m;
int main(){
    n = read(); tr.insert({inf, inf}); tr.insert({-inf, -inf});
    int cnt = 0; pai tmp;
    while(n--){
        int op, x;
        op = read(); x = read();
        if(op == 1) tr.insert({x, ++cnt});
        if(op == 2) tr.erase(tr.lower_bound({x, 0}));
        if(op == 3) write(tr.order_of_key(*tr.lower_bound({x, 0}))), putchar('\n');
        if(op == 4) write(tr.find_by_order(x) -> first), putchar('\n');
        if(op == 5) write((--tr.lower_bound({x, 0})) -> first), putchar('\n');
        if(op == 6) write(tr.upper_bound({x, inf}) -> first), putchar('\n');
    }
} 

翻最优解时看到一个好优美的封装平衡树

#include <algorithm>
//#include <cmath>
#include <cstdio>
#include <vector>
const int INF  = (1 << 30);
const int Q    = 100005;               ///< 平衡树元素个数
const int MAXX = 10000000;             ///< 元素最大值
const int T    = MAXX;                 ///< 当元素有负数时,要把它转为正数,即加上一个数,一般为max(abs(x)) = T
const int P    = 4472;  ///< 分块块数,当前请设为int(sqrt(MAXX + T))
const int PP   = (MAXX + T) / P;       ///< 每块大小,20000000 = 最大值 + T

using namespace std;
#define rg register int
char buf[1 << 23], *p1 = buf, *p2 = buf;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline bool ig(char c) { return c >= 48 && c <= 57; }
inline void read(int& oi) {
    char c;
    int  f = 1, res = 0;
    while (c = gc(), (!ig(c)) && c ^ '-')
        ;
    c ^ '-' ? res = (c ^ 48) : f = -1;
    while (c = gc(), ig(c)) res = res * 10 + (c ^ 48);
    oi = f * res;
}
inline void print(int oi) {
    if (oi < 0) putchar('-'), oi = ~oi + 1;
    if (oi > 9) print(oi / 10);
    putchar(oi % 10 + 48);
}
int n;
/**
 * @brief 用std::vector实现的小平衡树
 */
struct Vector {
    vector<int>           v;   ///< 平衡树主体
    vector<int>::iterator it;  ///< 用来访问
                               //    int                   sze;  ///< 大小
    /**
     * @brief 向平衡树中加入一个数x
     * @param x 要加入的数
     * @return null
     */
    inline void           Insert(int x) {
        it = lower_bound(v.begin(), v.end(), x);
        v.insert(it, x);
    }
    /**
     * @brief 在平衡树中删除一个数x
     * @param x 要删除的数
     * @return null
     */
    inline void Delete(int x) {
        it = lower_bound(v.begin(), v.end(), x);
        v.erase(it);
    }
    /**
     * @brief 求出x在平衡树中的排名,最小的数为第一名
     * @param x 要求排名的数
     * @return 排名
     */
    inline int rank(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; }
    /**
     * @brief 求出排名为x的数
     * @param x 排名x
     * @return 排名为x的数
     */
    inline int kth(int x) { return v[x - 1]; }
    /**
     * @brief 求出x的前驱,若没有前驱返回0
     * @param x 要求前驱的数
     * @return x的前驱
     */
    inline int pre(int x) {
        it = lower_bound(v.begin(), v.end(), x);
        return it == v.begin() ? 0 : (*(--it));
    }
    /**
     * @brief 求出x的后续,若没有后续返回0
     * @param x 要求后续的数
     * @return x的后续
     */
    inline int suf(int x) {
        it = upper_bound(v.begin(), v.end(), x);
        return it == v.end() ? 0 : (*it);
    }

    inline int min() { return !v.empty() ? suf(-INF) : 0; }  ///<平衡树中的最小值
    inline int max() { return !v.empty() ? pre(INF) : 0; }   ///<平衡树中的最大值
};
Vector V[P + 1];  ///< 块,V[0]是块的平衡树
/**
 * 最终的平衡树,分块实现,优化时间复杂度
 */
struct Devide {
    int         g[P + 1];  ///< 树状数组,维护sze
    /**
     * 将[x,P]中的数都加上y
     * @param x 左边界
     * @param y 加数
     */
    inline void addd(int x, int y) {
        for (rg i = x; i <= P; i += i & -i) g[i] += y;
    }
    /**
     * 求出[1,x]的和
     * @param x 右边界
     * @return 和
     */
    inline int qrry(int x) {
        int res = 0;
        for (rg i = x; i > 0; i -= i & -i) res += g[i];
        return res;
    }
    /**
     * 给[l,r]加上x
     * @param l 左边界
     * @param r 右边界
     * @param x 加数
     */
    inline void mddy(int l, int r, int x) {
        if (!l || !r || l > r) return;
        addd(l, x);       // [l,P]加上x
        addd(r + 1, -x);  //[r+1,P]减去x
    }
    int sze[P + 1];               ///< 每个块的元素个数
#define bl(x) ((x - 1) / PP + 1)  ///< 求出x在第几个数
    /**
     * 插入一个数
     * @param x 要插入的数
     */
    inline void Insert(int x) {
        x += T;                           // 离散化
        int blx = bl(x);                  // 求出x在哪个块
        if (!sze[blx]) V[0].Insert(blx);  // if(x==10543785){printf("%d\n",blx);system("pause");} // 如果之前没有这个块,就新建这个块
        ++sze[blx];                       // 块内的元素个数++
        mddy(blx, P, 1);                  // 对g进行更新
        V[blx].Insert(x);                 // 块内插入
    }
    /**
     * 删除一个数
     * @param x 要删除的数
     */
    inline void Delete(int x) {
        x += T;                           // 离散化
        int blx = bl(x);                  // 求出x是在哪个块
        --sze[blx];                       // 块元素--
        if (!sze[blx]) V[0].Delete(blx);  // 如果删掉这个块之后,块已经没有元素,删除这个块
        mddy(blx, P, -1);                 // 对g进行更新
        V[blx].Delete(x);                 // 块内删除
    }
    /**
     * 已知排名,求元素
     * @param x 排名
     * @return 元素
     */
    inline int kth(int x) {
        int L = 1, R = P;           ///< L:左边界 R:右边界
        while (L < R) {             // 双端闭区间,二分求第一个总元素个数>=x
            int mid = L + R >> 1;   // 取中值
            int tim = qrry(mid);    // 求出[1,mid]的块的元素个数
            if (tim >= x) R = mid;  // 如果可行,则>mid的肯定不是最优
            else L = mid + 1;       // 如果不可行,则<=mid的肯定都不可行
        }
        return V[L].kth(x - qrry(L - 1)) - T;  // x - qrry(L - 1) 求出在块内的排名,-T 把离散化转换回来
    }
    /**
     * 已知元素,求排名
     * @param x 元素
     * @return 排名
     */
    inline int rank(int x) {
        x += T;                   // 离散化
        int blx = bl(x);          // 求出x是在哪个块
        int res = qrry(blx - 1);  // 求出前面的块的元素个数
        return res + V[blx].rank(x);
    }
    /**
     * 求前驱,没有前驱返回0
     * @param x 要求前驱的元素
     * @return 前驱
     * @retval 0 没有前驱
     */
    inline int pre(int x) {
        x += T;                          // 离散化
        int blx = bl(x);                 // 求出x是在哪个块
        int tim = (V[blx].pre(x)) - T;   // 组内前驱
        if (tim ^ -T) return tim;        // 如果组内有前驱,返回前驱
        int ls = V[0].pre(blx);          // 否则,求出组的前驱
        if (ls) return V[ls].max() - T;  // 组的前驱的最大值
        return 0;
    }
    /**
     * 求后续,没有后续返回0
     * @param x 要求后续的元素
     * @return 后续
     * @return 0 没有后续
     */
    inline int suf(int x) {
        x += T;                          // 离散化
        int blx = bl(x);                 // 求出x是在哪个块
        int tim = (V[blx].suf(x)) - T;   // 组内后续
        if (tim ^ -T) return tim;        // 如果组内有后续,返回后续
        int rs = V[0].suf(blx);          // 否则,求出组的后续
        if (rs) return V[rs].min() - T;  // 组的后续的最大值
        return 0;
    }
} D;
int main() {
    read(n);
    while (n--) {
        int opt, x;
        read(opt);
        read(x);
        switch (opt) {
        case 1: D.Insert(x); break;
        case 2: D.Delete(x); break;
        case 3:
            print(D.rank(x));
            putchar('\n');
            break;
        case 4:
            print(D.kth(x));
            putchar('\n');
            break;
        case 5:
            print(D.pre(x));
            putchar('\n');
            break;
        case 6:
            print(D.suf(x));
            putchar('\n');
            break;
        }
    }
    return 0;
}
posted @ 2022-11-25 10:08  purplevine  阅读(27)  评论(0编辑  收藏  举报