[Luogu] P6136 [template] common balance tree (data enhanced version)

Title address:

https://www.luogu.com.cn/problem/P6136

Topic background:
This topic is the enhanced version of P3369 data, which expands the data range and adds mandatory online. The input and output of the question are slightly different from the original question, but the operations that need to be supported are the same.

Title Description:
You need to write a data structure (refer to the title) to maintain some integers. The following operations need to be provided:
1. Insert an integer x x x.
2. Delete an integer x x x (if there are multiple identical numbers, only one will be deleted).
3. Query integer x x Ranking of x (ranking is defined as the number of numbers smaller than the current number + 1).
4. Query ranking is x x The number of x (if it does not exist, it is considered that the ranking is less than x x The maximum number of x is guaranteed x x x does not exceed the total number of in the current data structure).
5. Beg x x Precursor of x (defined as less than x x x. And the maximum number).
6. Beg x x Successor of x (successor defined as greater than x x x. And the smallest number).
This question is forced to be online to ensure that all operations are legal 2 2 2 ensure that there is at least one x x x. Operation 4 , 5 , 6 4,5,6 4,5,6 (ensure that there is an answer).

Input format:
Two positive integers in the first line n , m n,m n. M represents the number of initial numbers and the number of operations.
Second line n n n integers a 1 , a 2 , a 3 , ... , a n a_1,a_2,a_3,\ldots,a_n a1, a2, a3,..., an denotes the initial number. next m m m lines, each line has two integers opt \text{opt} opt and x ′ x' x′, opt \text{opt} opt indicates the sequence number of the operation( 1 ≤ opt ≤ 6 1 \leq \text{opt} \leq 6 1≤opt≤6), x ′ x' x 'represents the encrypted operand. We remember last \text{last} Last means last time 3 , 4 , 5 , 6 3,4,5,6 The answers of 3, 4, 5 and 6 operations are the answers of each operation x ′ x' x 'must be XOR last \text{last} last is real x x x. Initial last \text{last} last is 0 0 0.

Output format:
Output one integer per line, representing all 3 , 4 , 5 , 6 3,4,5,6 3, 4, 5, 6 operate on the exclusive or sum of the answers.

Data range:
about 100 % 100\% 100% data, 1 ≤ n ≤ 1 0 5 1\leq n\leq 10^5 1≤n≤105, 1 ≤ m ≤ 1 0 6 1\leq m\leq 10^6 1≤m≤106, 0 ≤ a i , x < 2 30 0\leq a_i,x\lt 2^{30} 0≤ai​,x<230.

Fhq tree can be used for reference https://blog.csdn.net/qq_46105170/article/details/118997891 Please rank the following r r The operation of the number of r is different from the reference link. This operation can be done iteratively or recursively by using the method of ordinary balanced tree, or the operation of splitting by size can be considered. This operation is defined as follows:
Set the total number of numbers in the current tree as n n n (here) n n n is not the number of nodes, because a cnt will be recorded in each node to represent how many times this number appears. Of course, you can also save the values that appear multiple times in multiple nodes) k k k is a 1 ∼ n 1\sim n Number of 1 ∼ n, press k k k splitting means splitting a tree into two trees x x x and y y y. Among them x x The number of numbers of x is greater than or equal to k k The minimum value of k.
So the ranking is r r You can do this by pressing the number of r first r r r split, and then find the maximum value of the small tree.

The code is as follows:

#include <iostream>
using namespace std;

const int N = 2e6 + 10;
int n, m;
struct Node {
    int l, r;
    int v, rnd;
    int sz, cnt;
} tr[N];
int root, idx;
int x, y, z;
int res, last;

int get_node(int v) {
    tr[++idx].v = v;
    tr[idx].l = tr[idx].r = 0;
    tr[idx].sz = tr[idx].cnt = 1;
    tr[idx].rnd = rand();
    return idx;
}

void pushup(int u) {
    tr[u].sz = tr[tr[u].l].sz + tr[tr[u].r].sz + tr[u].cnt;
}

// Press key to split into two trees less than or equal to key and greater than key
void split(int u, int key, int &x, int &y) {
    if (!u) x = y = 0;
    else {
        if (tr[u].v <= key) {
            x = u;
            split(tr[u].r, key, tr[u].r, y);
            pushup(x);
        } else {
            y = u;
            split(tr[u].l, key, x, tr[u].l);
            pushup(y);
        }
    }
}

// Split according to sz and split into two trees. The size of the small tree is the smallest number greater than or equal to sz
void split_sz(int u, int sz, int &x, int &y) {
    if (!u) x = y = 0;
    else {
        if (sz > tr[tr[u].l].sz) {
            x = u;
            split_sz(tr[u].r, sz - tr[tr[u].l].sz - tr[u].cnt, tr[u].r, y);
            pushup(x);
        } else {
            y = u;
            split_sz(tr[u].l, sz, x, tr[u].l);
            pushup(y);
        }
    }
}

int merge(int x, int y) {
    if (!x || !y) return x | y;
    if (tr[x].rnd > tr[y].rnd) {
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;
    } else {
        tr[y].l = merge(x, tr[y].l);
        pushup(y);
        return y;
    }
}

int merge(int x, int y, int z) {
    return merge(merge(x, y), z);
}

void insert(int c) {
    split(root, c, y, z);
    split(y, c - 1, x, y);
    if (!y) y = get_node(c);
    else {
        tr[y].cnt++;
        tr[y].sz++;
    }

    root = merge(x, y, z);
}

void remove(int c) {
    split(root, c, y, z);
    split(y, c - 1, x, y);
    tr[y].cnt--;
    tr[y].sz--;
    if (!tr[y].cnt) y = 0;
    root = merge(x, y, z);
}

int get_rank_by_key(int c) {
    split(root, c - 1, x, y);
    int rk = tr[x].sz + 1;
    root = merge(x, y);
    return rk;
}

int get_key_by_rank(int rk) {
    split_sz(root, rk, x, y);
    int u = x, key;
    while (u) key = tr[u].v, u = tr[u].r;
    root = merge(x, y);
    return key;
}

int get_prev(int c) {
    split(root, c - 1, x, y);
    int u = x, key;
    while (u) key = tr[u].v, u = tr[u].r;
    root = merge(x, y);
    return key;
}

int get_next(int c) {
    split(root, c, x, y);
    int u = y, key;
    while (u) key = tr[u].v, u = tr[u].l;
    root = merge(x, y);
    return key;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        int c;
        scanf("%d", &c);
        insert(c);
    }

    while (m--) {
        int op, c;
        scanf("%d%d", &op, &c);
        c ^= last;
        
        if (op == 1) insert(c);
        else if (op == 2) remove(c);
        else {
            int w;
            if (op == 3) w = get_rank_by_key(c);
            else if (op == 4) w = get_key_by_rank(c);
            else if (op == 5) w = get_prev(c);
            else w = get_next(c);

            res ^= w;
            last = w;
        }
    }

    printf("%d\n", res);

    return 0;
}

Time complexity per operation O ( log ⁡ n ) O(\log n) O(logn)( n n n refers to the number of nodes in the tree during the operation O ( n ) O(n) O(n).

Tags: C++ Algorithm data structure

Posted on Sat, 27 Nov 2021 21:21:26 -0500 by Desbrina