权值线段树

权值线段树就是一棵线段树,不过存的值不是和或积或最大值一类的,而是这一区间上“数”的个数。

这里就讲一下动态开点的。

1,存储

struct seg_tree{
    int val, lson, rson;//个数、左孩子编号、右孩子编号
}st[MAX];

 

 2,加点

void add(int &x,int l, int r, int v) {
    if (!x) x = ++tot;//动态开点 
    st[x].val++;
    if (l == r) return;
    ll mid = (l + r) >> 1;
    if (mid >= v) add(st[x].lson, l, mid, v); 
    else add(st[x].rson, mid + 1, r, v);
}

 

它有什么功能呢?

其实它就是一个桶,桶能做的它都能做。

1,查询v出现的次数(单点查询)

void ask(int x, int l, int r, int v) {
    if (!x) return 0;
    if (l == r) return st[x].val;
    int mid = (l + r) >> 1;
    if (v <= mid) return ask(st[x].lson, l, mid, v);
    else return ask(st[x].rson, mid + 1, r, v);
}

 

2,查询[l, r]中的数出现的次数

以下代码是求[i, j]中的数出现的次数

int ask(int x, int l, int r, int i, int j) {
    if (!x) return 0;
    if (i == l && r == j) {
        return st[x].val;
    }
    int mid = (l + r) >> 1;
    if (j <= mid) return ask(st[x].lson, l, mid, i, j);
    else if (i > mid) return ask(st[x].rson, mid + 1, r, i, j);
    else return ask(st[x].lson, l, mid, i, mid) + ask(st[x].rson, mid + 1, r, mid + 1, j);
}

 

3,查询区间第k大(小)

int ask(int x, int l, int r, int k) {
    if (l == r) return l;
    int mid = (l + r) >> 1;
    if (k <= st[st[x].lson].val) return ask(st[x].lson, l, mid, k);
    else return ask(st[x].rson, mid + 1, r, k st[st[x].lson].val);
}

 

大概就以上几种用法,相信你都学会啦。

你可能感兴趣的:(权值线段树)