Treap 20pts,评测机进入了本不该进的if语句(本地测试没问题)
查看原帖
Treap 20pts,评测机进入了本不该进的if语句(本地测试没问题)
324632
Skeleton_Huo楼主2022/8/26 11:17
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

const int INF = 0x3f3f3f3f;

inline int read() {
    char ch = getchar(); int flag = 1, ans = 0;
    while (ch < '0' || ch > '9') { if (ch == '-') flag = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar(); }
    return flag * ans;
}

struct Node {
    Node* ch[2];    // 两个子节点的地址
    int val, rank;
    int rep_cnt;    // val出现的次数
    int siz;        // 子树点数
    Node (int v) : val(v), rep_cnt(1), siz(1) {
        ch[0] = ch[1] = nullptr;
        rank = rand();
    }
    void upd_siz() {
        // 用于旋转和删除过后, 重新计算siz的值
        siz = rep_cnt;
        if (ch[0] != nullptr) siz += ch[0]->siz;
        if (ch[1] != nullptr) siz += ch[1]->siz;
    }
};

class Treap {
private:
    Node* root;

    /* 旋转, 0为左旋, 1为右旋  单旋只需考虑两个旋转节点的左右子树及父亲*/
    void _rotate(Node*& cur, int dir) {
        Node* tmp = cur->ch[!dir];   // tmp临时指向新根(方便)
        cur->ch[!dir] = tmp->ch[dir];   // cur未来的右/左子树为其左/右的右/左子树
        tmp->ch[dir] = cur;
        cur->upd_siz(), tmp->upd_siz(); // 更新大小信息
        cur = tmp;
    }

    // 树上操作皆使用分治思想解决
    // 插入
    void _insert(Node*& cur, int val) {
        if (cur == nullptr) {
            cur = new Node(val);
            return;
        }
        if (val == cur->val) {
            cur->rep_cnt++;
            cur->siz++;
            return;
        }
        if (val < cur->val) {
            _insert(cur->ch[0], val);
            if (cur->ch[0]->rank < cur->rank) _rotate(cur, 1);
            cur->upd_siz();     // 大小变化, 需要更新 (注意_rotate的更新不能替代这次)
        } else {
            _insert(cur->ch[1], val);
            if (cur->ch[1]->rank < cur->rank) _rotate(cur, 0);
            cur->upd_siz();
        }
    }

    // 删除, 需分类讨论
    void _del(Node*& cur, int val) {
        if (val < cur->val) {
            _del(cur->ch[0], val);
            cur->upd_siz();
        } else if (val > cur->val) {
            _del(cur->ch[1], val);
            cur->upd_siz();
        } else {
            if (cur->rep_cnt > 1) {
                cur->rep_cnt--, cur->siz--;
                return;
            }
            int state = 0;
            state |= (cur->ch[0] != nullptr);
            state |= ((cur->ch[1] != nullptr) << 1);
            // 位0为是否有左子树, 位1为是否有右子树
            Node* tmp = cur;
            if (state == 0) {
                delete cur;
                cur = nullptr;
            } else if (state == 1) {
                cur = tmp->ch[0];
                delete tmp;
            } else if (state == 2) {
                cur = tmp->ch[1];
                delete tmp;
            } else {
                int dir = cur->ch[0]->rank < cur->ch[1]->rank ? 1 : 0;
                // 若左边rank小就右旋将左儿子提上去, 右边同理
                _rotate(cur, dir);
                _del(cur->ch[dir], val);
                cur->upd_siz();
            }
        }
    }

    // 根据值查询排名
    int _query_rank(Node* cur, int val) {
        int lc_siz = cur->ch[0] == nullptr ? 0 : cur->ch[0]->siz;
        // 这个树中小于val的节点的数量
        if (val == cur->val) return lc_siz + 1;       // 若该节点为目标
        else if (val < cur->val) {
            if (cur->ch[0] != nullptr)
                return _query_rank(cur->ch[0], val);
            else return 1;      // 如果左子树是空的, 返回小于val的数的个数+1, 即将val插入后的位置
        } else {
            if (cur->ch[1] != nullptr)
                return lc_siz + cur->rep_cnt + _query_rank(cur->ch[1], val);
            else return cur->siz + 1;   // 相当于lc_siz + cur->rep_cnt + 1
        }
    }

    // 根据排名查询值
    int _query_val(Node* cur, int rank) {
        if (cur == nullptr) return -INF;
        int lc_siz = cur->ch[0] == nullptr ? 0 : cur->ch[0]->siz;
        // 左子树大小
        if (rank <= lc_siz)
            return _query_val(cur->ch[0], rank);
        else if (rank <= lc_siz + cur->rep_cnt)
            return cur->val;
        else
            return _query_val(cur->ch[1], rank - lc_siz - cur->rep_cnt);
    }
    
    // 查询第一个比val小的节点, 可转换为找第一个<=val-1的值
    int _query_prev(Node* cur, int val) {
        // if (cur == nullptr) return -INF;
        if (cur->val == val - 1) return cur->val;
        if (val - 1 < cur->val)
            return _query_prev(cur->ch[0], val);
        if (val - 1 > cur->val)
            if (cur->ch[1] == nullptr) return cur->val;
            else return _query_prev(cur->ch[1], val);
    }

    // 查询第一个比val大的节点, 可转换为找第一个>=val+1的值
    int _query_next(Node* cur, int val) {
        // if (cur == nullptr) return -INF;
        if (cur->val == val + 1) return cur->val;
        if (val + 1 > cur->val)
            return _query_next(cur->ch[1], val);
        if (val + 1 < cur->val)
            if (cur->ch[0] == nullptr) return cur->val;
            else return _query_next(cur->ch[0], val);
    }

public:
    void insert(int val) { _insert(root, val); }
    void del(int val) { _del(root, val); }
    int query_rank(int val) { return _query_rank(root, val); }
    int query_val(int val) { return _query_val(root, val); }
    int query_prev(int val) { return _query_prev(root, val); }
    int query_next(int val) { return _query_next(root, val); }
};

Treap tr;

int main() {
    // freopen("a.in", "r", stdin);
    // freopen("a.out", "w", stdout);

    srand(0);
    int n = read();

    while (n--) {
        int opt = read(), x = read();
        if (opt == 1) tr.insert(x);
        else if (opt == 2) tr.del(x);
        else if (opt == 3) printf("%d\n", tr.query_rank(x));
        else if (opt == 4) printf("%d\n", tr.query_val(x));
        else if (opt == 5) printf("%d\n", tr.query_prev(x));
        else printf("%d\n", tr.query_next(x));
    }
    
    // system("pause");
    // fclose(stdin);
    // fclose(stdout);
    return 0;
}

第一个点(即样例)就RE了,但本地测试没有问题,求dalao指点

2022/8/26 11:17
加载中...