"Chairman of the tree" may persist segment tree template

Learning segment tree premise of sustainable Notes

Persistence may be collectively referred to as a data structure, and they are also some features is the ability to save version history , and today we can say that the persistence segment tree is a data structure that preserves historical version

Algorithms content

Competition point need to use

Space 1, may be persistent segment tree of large consumption, note the use of the data range

2, persistent segment tree for zone problems can be solved, but the basic form is similar to a different code, we need to master the Chairman of the tree of principle and meaning of the code

Persistence may seek the k segment tree speak a little big problem

Persistable segment tree can maintain a lot of things, we are here to pick a more common terms,(The algorithm for people like me, it is quite difficult to watch the weigh themselves). Consider a problem, every edit to retain a timestamp, then we will ask each access a range of issues on a time stamp, it is clear that the normal segment tree does not meet our needs, we may consider persistence writing, if modified to a single point, then each modification will change \ (logn \) nodes, a change in thinking, we can modify the equivalent of more open \ (logn \) these values after the nodes to save the changes because other nodes unchanged, so we can share these nodes.

The common node? What do you mean, you can refer to the diagram (Los solution to a problem Valley pick, really I do not want to draw)

Definition: orange front is changed, but only change the blue [1,4] [3,4] [4,4] for the new point

We found that the orange [1,4] and blue [1,4] Shared [1,2] this point, [1,2] Needless to say sub-tree of course, can be done so that we can persistence operations, but there is such a problem is how they know how each version of the situation? We need to use an array to hold the number of nodes, so that we can easily feedback from a version of the

After solving these circumstances, we consider this question, the analysis \ (k \) before a big thing that we need to consider, in the \ ([l, r] \ ) interval looking for your first \ (k \) large, this \ ([l, r] \ ) section how to do, when you analyze here, when in fact the answer also ready to come out, with the prefix and content maintenance intervals , what does that mean? We each leaf node to a number, each number is the number of interval contained as a weight tree line , then there is every prefix with the first number, and is a version, so \ ([ 1, l] \) is a segment tree can be persistent, then \ ([1, r] \ ) is a segment tree can be persistent, hey because we are using a prefix and carry out achievements, it is not always versions meet the prefix and the nature of it? Of course meet, that we want to ask \ ([l, r] \ ) section of \ (k \) large, we can use \ ([1.R] - [1, L - 1] \) , so is our \ ([l, r] \ ) a

Meet the requirements of intervals, let's meet our first \ (k \) large requirements, we assume now have obtained a \ ([l, r] \ ) This version of the weight of the tree line, seeking the first \ (k \ ) large, we consider the left subtree, found that the number is more than equal to \ (k \) , it is clear that our answer on the left. If less than \ (k \) , it is clear that our answer right, you'll Wangyoubianzou, but note that when Wangyoubianzou our first \ (k \) big becomes \ (k \) - Left subtree ( \ ([. 1, MID] \) ) included in the number, the drawing can understand their own

This, we can write the code

K may be a large demand on the persistence of the code segment tree exhibit

And the tree line, as there is a contribution

//#define fre yes

#include <cstdio>

const int N = 1000005;
int T[N];
struct Node {
    int l, r, interval;
} tree[N << 5];

int cnt; //点的个数
void build(int l, int r) {
    int rt = ++cnt;
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].interval = 0;
    if(l == r) return ;
    
    int mid = (l + r) >> 1;
    build(l, mid);
    build(mid + 1, r);
}

int main() {
    build(1, m);
}

Then a single point modification

int update(int pre, int l, int r, int x) { //update(T[g], 1, m, x) //g代表哪次版本
    int rt = ++cnt;
    tree[rt].l = tree[pre].l;
    tree[rt].r = tree[prt].r;
    tree[rt].interval = tree[pre].interval;
    if(l == r) return rt;
    int mid = (l + r) >> 1;
    if(mid >= x) tree[rt].l = (tree[pre].l, l, mid, x);
    else tree[rt].r = (tree[pre].r, mid + 1, r, x);
    return rt;
}

Then a single point of inquiry

int query(int u, int v, int l, int r, int x) {
    if(l == r) return l;
    int t = tree[tree[v].l] - tree[tree[u].l];
    int mid = (l + r) >> 1;
    if(t >= x) return query(tree[u].l, tree[v].l, l, mid, x);
    else return query(tree[u].r, tree[v].r, mid + 1, r, x - t);
}

And finally put an example Luo Gu P3834

The complete code

//#define fre yes

#include <cstdio>
#include <algorithm>

const int N = 200005;
int a[N], b[N], T[N];

struct Node {
    int l, r, sum;
} tree[N << 5];

int cnt;
void build(int l, int r) {
    int rt = ++cnt;
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].sum = 0;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    build(l, mid);
    build(mid + 1, r);
}

int update(int pre, int l, int r, int x) {
    int rt = ++cnt;
    tree[rt].l = tree[pre].l;
    tree[rt].r = tree[pre].r;
    tree[rt].sum = tree[pre].sum + 1;
    if(l == r) return rt;
    int mid = (l + r) >> 1;
    if(mid >= x) tree[rt].l = update(tree[pre].l, l, mid, x);
    else tree[rt].r = update(tree[pre].r, mid + 1, r, x);
    return rt;
}

int query(int u, int v, int l, int r, int x) {
    if(l == r) return l;
    int sum = tree[tree[v].l].sum - tree[tree[u].l].sum;
    int mid = (l + r) >> 1;
    if(sum >= x) return query(tree[u].l, tree[v].l, l, mid, x);
    else return query(tree[u].r, tree[v].r, mid + 1, r, x - sum);
}

int main() {
    static int n, q;
    scanf("%d %d", &n, &q);
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    std::sort(b + 1, b + 1 + n);
    int m = std::unique(b + 1, b + 1 + n) - b - 1;

    T[0] = 0;
    build(1, m);
    for (int i = 1; i <= n; i++) {
        int t = std::lower_bound(b + 1, b + 1 + m, a[i]) - b;
        T[i] = update(T[i - 1], 1, m, t);
    }

    for (int i = 1; i <= q; i++) {
        int x, y, z;
        scanf("%d %d %d", &x, &y, &z);
        int t = query(T[x - 1], T[y], 1, m, z);
        printf("%d\n", b[t]);
    } return 0;
}

Guess you like

Origin www.cnblogs.com/Nicoppa/p/11484903.html