权值线段树就是一棵线段树,不过存的值不是和或积或最大值一类的,而是这一区间上“数”的个数。
这里就讲一下动态开点的。
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); }
大概就以上几种用法,相信你都学会啦。
权值线段树也没什么例题,但它是很多高端数据结构的基础。